is a community-driven effort and is not affiliated with the official Hotwire project. Click here to learn more »

Smooth page refreshes with morphing

Turbo Drive makes navigation faster by avoiding full-page reloads. But there is a scenario where Turbo can raise the fidelity bar further: loading the current page again (page refresh).

A typical scenario for page refreshes is submitting a form and getting redirected back. In such scenarios, sensations significantly improve if only the changed contents get updated instead of replacing the <body> of the page. Turbo can do this on your behalf with morphing and scroll preservation.



You can configure how Turbo handles page refresh with a <meta name="turbo-refresh-method"> in the page’s head.

  <meta name="turbo-refresh-method" content="morph">

The possible values are morph or replace (the default). When it is morph, when a page refresh happens, instead of replacing the page’s <body>, Turbo will only update the DOM elements that have changed, keeping the rest untouched. This approach delivers better sensations because it keeps the screen state.

Under the hood, Turbo uses the fantastic idiomorph library.

Scroll preservation

You can configure how Turbo handles scrolling with a <meta name="turbo-refresh-scroll"> in the page’s head.

  <meta name="turbo-refresh-scroll" content="preserve">

The possible values are preserve or reset (the default). When it is preserve, when a page refresh happens, Turbo will keep the page’s vertical and horizontal scroll.

Exclude sections from morphing

Sometimes, you want to ignore certain elements while morphing. For example, you might have a popover that you want to keep open when the page refreshes. You can flag such elements with data-turbo-permanent, and Turbo won’t attempt to morph them.

<div data-turbo-permanent>...</div>

Turbo frames

You can use turbo frames to define regions in your screen that will get reloaded using morphing when a page refresh happens. To do so, you must flag those frames with refresh="morph".

<turbo-frame id="my-frame" refresh="morph">

With this mechanism, you can load additional content that didn’t arrive in the initial page load (e.g., pagination). When a page refresh happens, Turbo won’t remove the frame contents; instead, it will reload the turbo frame and render its contents with morphing.

Broadcasting page refreshes

There is a new turbo stream action called refresh that will trigger a page refresh:

<turbo-stream action="refresh"></turbo-stream>

Server-side frameworks can leverage these streams to offer a simple but powerful broadcasting model: the server broadcasts a single general signal, and pages smoothly refresh with morphing.

You can see how the turbo-rails gem does it for Rails:

# In the model
class Calendar < ApplicationRecord

# View
turbo_stream_from @calendar