The Life‑Changing Magic of Ruby and Rails

Turbo Drive Essentials

I spent the last night reading up on the Turbo Drive, a part of Hotwire front-end framework that Rails 7 ships with. The core value proposition of Hotwire is that all the logic lives on the server, and the browser deals just with the final HTML. This post tries to summarize my notes.

How does it work?

Turbo Drive intercepts all clicks on anchor links to the same domain. When you click a link, Turbo Drive does the following:

  1. Prevent the browser from following the link,
  2. Change the browser URL using the History API,
  3. Request the new page using a fetch request
  4. Render the response HTML by
  • replacing the current <body> element with the response
  • merging the <head> element’s content.

The JavaScript window and document objects and the <html> element persist from one rendering to the next. It’s possible to interact with Turbo Drive to control the visits by hooking into the request’s lifecycle.

The same goes for an HTML form. Turbo Drive converts Form submissions turned into fetch requests. Then it follows the redirect and renders the HTML response.

There are two types of visits:

Application Visit

  1. Initiated by clicking a link or programmatically by calling Turbo.visit(location).
  2. Always issues a network request.
  3. Action: advance (default) or replace
  4. To skip pushing a new history entry, use the data-turbo-action="replace" attribute or pass { action: “replace” } option to Turbo.visit.

Restoration Visit: Restore

  1. Used when you navigate with the browser’s Back or Forward button.
  2. If possible, Turbo Drive will render a copy of the page from the cache without making a request. Otherwise, it will retrieve a fresh copy of the page over the network.
  3. Action: restore (used internally; don’t annotate the link or invoke Turbo.visit with restore action. )

Events

  • turbo:before-visit: use to cancel a visit before it starts
  • turbo:before-fetch-request: use to pause request and make additional preparations before making the request
  • turbo:before-render: use to pause rendering and make additional preparation before rendering.

Perform Visits with Different Method

By default, Turbo links send a GET request to the server. You can change this with the data-turbo-method attribute.

<a href="/articles/54" data-turbo-method="delete">Delete the article</a>

Note: This link can’t appear inside a form, as Turbo converts it to a hidden form next to the anchor element, and you can’t have nested forms.

It’s recommended to use actual forms and buttons for anything that’s not a GET.

Annotate the element or any of its ancestors with data-turbo="false".

<div data-turbo="false">
  <a href="/">Disabled</a>
  <form action="/messages" method="post">
    ...
  </form>
</div>

The browser handles the links or forms as usual, when Turbo Drive is disabled.

To enable when an ancestor has opted out, set it to true.

<div data-turbo="false">
  <a href="/" data-turbo="true">Enabled</a>
</div>

To make Turbo Drive opt-in rather than opt-out, first set the following:

Turbo.session.drive = false

Then, enable it on a per-element basis by setting data-turbo="true".

Progress Bar

Enabled by default, and shows for any request that takes longer than 500 ms to load. Change this delay with:

Turbo.setProgressBarDelay(time)

To override the styles, use the following:

.turbo-progress-bar {
  height: 5px;
  background-color: green;
  visibility: hidden; // to hide the progress-bar
}

Reloading When Assets Change

Turbo Drive can track the URLs of the asset elements in the <head> tag from one page to the next, automatically issuing a full reload if it was changed. So users always have the latest versions of your application’s scripts and styles.

For this to work, annotate assets with data-turbo-track="reload" and include a version identifier on the asset URLs.

Form Submissions

Throughout a submission, Turbo Drive will dispatch a series of events that target the <form> element and bubble up through the document:

  1. turbo:submit-start
  2. turbo:before-fetch-request
  3. turbo:before-fetch-response
  4. turbo:submit-end

Redirect After Form Submission

After a stateful request from a form submission, Turbo Drive expects the server to return an HTTP 303 redirect response. It follows the redirect, and navigates and updates the page without reloading.

Streaming After a Form Submission

Servers may also respond to form submissions with a Turbo Streams message by sending the header Content-Type: text/vnd.turbo-stream.html followed by one or more elements in the response body. This lets you update multiple parts of the page without navigating.

Subscribe to Akshay's Blog

Sign up now to get access to the library of members-only issues.
Jamie Larson
Subscribe