<body>, and merges its
<head>, all without incurring the cost of a full page load.
Turbolinks works in all modern desktop and mobile browsers. It depends on the HTML5 History API and Window.requestAnimationFrame. In unsupported browsers, Turbolinks gracefully degrades to standard navigation.
Turbolinks automatically initializes itself when loaded via a standalone
Your Ruby on Rails application can use the
turbolinks RubyGem to install Turbolinks. This gem contains a Rails engine which integrates seamlessly with the Rails asset pipeline.
turbolinksgem, version 5, to your Gemfile:
gem 'turbolinks', '~> 5.0.0'
The gem also provides server-side support for Turbolinks redirection.
turbolinks package to your application:
npm install --save turbolinks.
var Turbolinks =Turbolinksstart
Turbolinks intercepts all clicks on
<a href> links to the same domain. When you click an eligible link, Turbolinks prevents the browser from following it. Instead, Turbolinks changes the browser’s URL using the History API, requests the new page using
XMLHttpRequest, and then renders the HTML response.
During rendering, Turbolinks replaces the current
<body> element outright and merges the contents of the
document objects, and the HTML
<html> element, persist from one rendering to the next.
Turbolinks models navigation as a visit to a location (URL) with an action.
Visits represent the entire navigation lifecycle from click to render. That includes changing browser history, issuing the network request, restoring a copy of the page from cache, rendering the final response, and updating the scroll position.
There are two types of visit: an application visit, which has an action of advance or replace, and a restoration visit, which has an action of restore.
Application visits are initiated by clicking a Turbolinks-enabled link, or programmatically by calling
An application visit always issues a network request. When the response arrives, Turbolinks renders its HTML and completes the visit.
If possible, Turbolinks will render a preview of the page from cache immediately after the visit starts. This improves the perceived speed of frequent navigation between the same pages.
If the visit’s location includes an anchor, Turbolinks will attempt to scroll to the anchored element. Otherwise, it will scroll to the top of the page.
Application visits result in a change to the browser’s history; the visit’s action determines how.
The default visit action is advance. During an advance visit, Turbolinks pushes a new entry onto the browser’s history stack using
Applications using the Turbolinks iOS adapter typically handle advance visits by pushing a new view controller onto the navigation stack. Similarly, applications using the Android adapter typically push a new activity onto the back stack.
You may wish to visit a location without pushing a new history entry onto the stack. The replace visit action uses
history.replaceState to discard the topmost history entry and replace it with the new location.
To specify that following a link should trigger a replace visit, annotate the link with
To programmatically visit a location with the replace action, pass the
action: "replace" option to
Applications using the Turbolinks iOS adapter typically handle replace visits by dismissing the topmost view controller and pushing a new view controller onto the navigation stack without animation.
Turbolinks automatically initiates a restoration visit when you navigate with the browser’s Back or Forward buttons. Applications using the iOS or Android adapters initiate a restoration visit when moving backward in the navigation stack.
If possible, Turbolinks will render a copy of the page from cache without making a request. Otherwise, it will retrieve a fresh copy of the page over the network. See Understanding Caching for more details.
Turbolinks saves the scroll position of each page before navigating away and automatically returns to this saved position on restoration visits.
Restoration visits have an action of restore and Turbolinks reserves them for internal use. You should not attempt to annotate links or invoke
Turbolinks.visit with an action of
Application visits can be canceled before they start, regardless of whether they were initiated by a link click or a call to
Listen for the
turbolinks:before-visit event to be notified when a visit is about to start, and use
$event.originalEvent.data.url, when using jQuery) to check the visit’s location. Then cancel the visit by calling
Restoration visits cannot be canceled and do not fire
turbolinks:before-visit. Turbolinks issues restoration visits in response to history navigation that has already taken place, typically via the browser’s Back or Forward buttons.
Turbolinks can be disabled on a per-link basis by annotating a link or any of its ancestors with
To reenable when an ancestor has opted out, use
Links with Turbolinks disabled will be handled normally by the browser.
document objects retain their state across page changes, and any other objects you leave in memory will stay in memory.
With awareness and a little extra care, you can design your application to gracefully handle this constraint without tightly coupling it to Turbolinks.
DOMContentLoaded, or jQuery
ready events. With Turbolinks, these events will fire only in response to the initial page load—not after any subsequent page changes.
In many cases, you can simply adjust your code to listen for the
turbolinks:load event, which fires once on the initial page load and again after every Turbolinks visit.
When possible, avoid using the
turbolinks:load event to add event listeners directly to elements on the page body. Instead, consider using event delegation to register event listeners once on
Your browser automatically loads and evaluates any
<script> elements present on the initial page load.
When you navigate to a new page, Turbolinks looks for any
<script> elements in the new page’s
<head> that aren’t present on the current page. Then it appends them to the current
<script> elements in a page’s
turbolinks:load event instead.
<script> elements with
data-turbolinks-eval="false" if you do not want Turbolinks to evaluate them after rendering. Note that this annotation will not prevent your browser from evaluating scripts on the initial page load.
Turbolinks maintains a cache of recently visited pages. This cache serves two purposes: to display pages without accessing the network during restoration visits, and to improve perceived performance by showing temporary previews during application visits.
When navigating by history (via Restoration Visits), Turbolinks will restore the page from cache without loading a fresh copy from the network, if possible.
Otherwise, during standard navigation (via Application Visits), Turbolinks will immediately restore the page from cache and display it as a preview while simultaneously loading a fresh copy from the network. This gives the illusion of instantaneous page loads for frequently accessed locations.
Turbolinks saves a copy of the current page to its cache just before rendering a new page. Note that Turbolinks copies the page using
cloneNode(true), which means any attached event listeners and associated data are discarded.
Listen for the
turbolinks:before-cache event if you need to prepare the document before Turbolinks caches it. You can use this event to reset forms, collapse expanded UI elements, or tear down any third-party widgets so the page is ready to be displayed again.
Turbolinks adds a
data-turbolinks-preview attribute to the
<html> element when it displays a preview from cache. You can check for the presence of this attribute to selectively enable or disable behavior when a preview is visible.
if documentdocumentElement// Turbolinks is displaying a preview
You can control caching behavior on a per-page basis by including a
<meta name="turbolinks-cache-control"> element in your page’s
<head> and declaring a caching directive.
no-preview directive to specify that a cached version of the page should not be shown as a preview during an application visit. Pages marked no-preview will only be used for restoration visits.
To specify that a page should not be cached at all, use the
no-cache directive. Pages marked no-cache will always be fetched over the network, including during restoration visits.
To completely disable caching in your application, ensure every page contains a no-cache directive.
Often you’ll want to perform client-side transformations to HTML received from the server. For example, you might want to use the browser’s knowledge of the user’s current time zone to group a collection of elements by date.
Suppose you have annotated a set of elements with
Consider what happens if you’ve configured this function to run on
turbolinks:load. When you navigate to the page, your function inserts date headers. Navigate away, and Turbolinks saves a copy of the transformed page to its cache. Now press the Back button—Turbolinks restores the page, fires
turbolinks:load again, and your function inserts a second set of date headers.
To avoid this problem, make your transformation function idempotent. An idempotent transformation is safe to apply multiple times without changing the result beyond its initial application.
One technique for making a transformation idempotent is to keep track of whether you’ve already performed it by setting a
data attribute on each processed element. When Turbolinks restores your page from cache, these attributes will still be present. Detect these attributes in your transformation function to determine which elements have already been processed.
A more robust technique is simply to detect the transformation itself. In the date grouping example above, that means checking for the presence of a date divider before inserting a new one. This approach gracefully handles newly inserted elements that weren’t processed by the original transformation.
Turbolinks may not be the only source of page updates in your application. New HTML can appear at any time from Ajax requests, WebSocket connections, or other client-side rendering operations, and this content will need to be initialized as if it came from a fresh page load.
In particular, these APIs give you callbacks when elements are attached to and removed from the document. You can use these callbacks to perform transformations and register or tear down behavior as soon as matching elements appear on the page, regardless of how they were added.
By taking advantage of
MutationObserver, Custom Elements, and idempotent transformations, there’s little need to couple your application to Turbolinks’ events.
Turbolinks allows you to mark certain elements as permanent. Permanent elements persist across page loads, so that any changes you make to those elements do not need to be reapplied after navigation.
Now imagine a user who has navigated to several pages in this application. She adds an item to her cart, then presses the Back button in her browser. Upon navigation, Turbolinks restores the previous page’s state from cache, and the cart item count erroneously changes from 1 to 0.
You can avoid this problem by marking the counter element as permanent. Designate permanent elements by giving them an HTML
id and annotating them with
Before each render, Turbolinks matches all permanent elements by
id and transfers them from the original page to the new page, preserving their data and event listeners.
During Turbolinks navigation, the browser will not display its native progress indicator. Turbolinks installs a CSS-based progress bar to provide feedback while issuing a request.
The progress bar is enabled by default. It appears automatically for any page that takes longer than 500ms to load.
The progress bar is a
<div> element with the class name
turbolinks-progress-bar. Its default styles appear first in the document and can be overridden by rules that come later.
For example, the following CSS will result in a thick green progress bar:
To disable the progress bar entirely, set its
visibility style to
Turbolinks can track the URLs of asset elements in
<head> from one page to the next, and automatically issue a full reload if they change. This ensures that users always have the latest versions of your application’s scripts and styles.
Annotate asset elements with
data-turbolinks-track="reload" and include a version identifier in your asset URLs. The identifier could be a number, a last-modified timestamp, or better, a digest of the asset’s contents, as in the following example.
You can use asset tracking with any HTML element, such as
<script>, or even
<meta>. An element annotated with
data-turbolinks-track="reload" will trigger a full reload if it changes in any way, e.g. if its attributes are not identical, or if the element is present on one page but not on the next.
Note that Turbolinks will only consider tracked assets in
<head> and not elsewhere on the page.
By default, Turbolinks only loads URLs with the same origin—i.e. the same protocol, domain name, and port—as the current document. A visit to any other URL falls back to a full page load.
In some cases, you may want to further scope Turbolinks to a path on the same origin. For example, if your Turbolinks application lives at
/app, and the non-Turbolinks help site lives at
/help, links from the app to the help site shouldn’t use Turbolinks.
<meta name="turbolinks-root"> element in your pages’
<head> to scope Turbolinks to a particular root location. Turbolinks will only load same-origin URLs that are prefixed with this path.
When you visit location
/one and the server redirects you to location
/two, you expect the browser’s address bar to display the redirected URL.
However, Turbolinks makes requests using
XMLHttpRequest, which transparently follows redirects. There’s no way for Turbolinks to tell whether a request resulted in a redirect without additional cooperation from the server.
To work around this problem, send the
Turbolinks-Location header in response to a visit that was redirected, and Turbolinks will replace the browser’s topmost history entry with the value you provide.
The Turbolinks Rails engine sets
Turbolinks-Location automatically when using
redirect_to in response to a Turbolinks visit.
Submitting an HTML form to the server and redirecting in response is a common pattern in web applications. Standard form submission is similar to navigation, resulting in a full page load. Using Turbolinks you can improve the performance of form submission without complicating your server-side code.
Turbolinks.visit to be evaluated by the browser.
If form submission results in a state change on the server that affects cached pages, consider clearing Turbolinks’ cache with
The Turbolinks Rails engine performs this optimization automatically for non-GET XHR requests that redirect with the
You can observe the
turbolinks:request-start event to set custom headers on Turbolinks requests. Access the request’s XMLHttpRequest object via
event.data.xhr, then call the
setRequestHeader method as many times as you wish.
For example, you might want to include a request ID with every Turbolinks link click and programmatic visit.
Performs an Application Visit to the given location (a string containing a URL or path) with the specified action (a string, either
If location is a cross-origin URL, or falls outside of the specified root (see Setting a Root Location), or if the value of
false, Turbolinks performs a full page load by setting
If action is unspecified, Turbolinks assumes a value of
Before performing the visit, Turbolinks fires a
turbolinks:before-visit event on
document. Your application can listen for this event and cancel the visit with
event.preventDefault() (see Canceling Visits Before They Start).
Removes all entries from the Turbolinks page cache. Call this when state has changed on the server that may affect cached pages.
if Turbolinkssupported// ...
Detects whether Turbolinks is supported in the current browser (see Supported Browsers).
Turbolinks emits events that allow you to track the navigation lifecycle and respond to page loading. Except where noted, Turbolinks fires events on the
turbolinks:click fires when you click a Turbolinks-enabled link. The clicked element is the event target. Access the requested location with
event.data.url. Cancel this event to let the click fall through to the browser as normal navigation.
turbolinks:before-visit fires before visiting a location, except when navigating by history. Access the requested location with
event.data.url. Cancel this event to prevent navigation.
turbolinks:visit fires immediately after a visit starts.
turbolinks:request-start fires before Turbolinks issues a network request to fetch the page. Access the XMLHttpRequest object with
turbolinks:request-end fires after the network request completes. Access the XMLHttpRequest object with
turbolinks:before-cache fires before Turbolinks saves the current page to cache.
turbolinks:before-render fires before rendering the page. Access the new
<body> element with
turbolinks:render fires after Turbolinks renders the page. This event fires twice during an application visit to a cached location: once after rendering the cached version, and again after rendering the fresh version.
turbolinks:load fires once after the initial page load, and again after every Turbolinks visit. Access visit timing metrics with the
We welcome contributions in the form of bug reports, pull requests, or thoughtful discussions in the GitHub issue tracker.
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
$ gem install bundler$ bundle install$ bin/blade build
Follow the instructions for Building From Source above. Then run
bin/blade runner and visit the displayed URL in your browser. The Turbolinks test suite will start automatically.
© 2017 Basecamp, LLC