Optimistic UI with Turbo 8 Morphs

Provide Optimistic UI updates using inline Turbo Stream Actions, and reconcile using Turbo 8 Morphs

View Solution on Patreon
Optimistic UI with Turbo 8 Morphs

Premise

The case of choosing between a SPA and a SSR approach boils down to who owns rendering the presentation. Having the server render it, as it is the case in Turbo, decreases programming complexity a lot. But since you always have to wait for any server response to advance the UI, it can feel sluggish, because of the latency involved.

Let’s do a little bit of napkin math. For example, let’s assume our server lives in Chicago, and the client is located in Amsterdam. According to Google, that’s a linear distance of 6,604 km. So, taking the speed of light into account, the lowest possible latency is 22ms, one way. N.B., that’s assuming a linear connection, no infrastructure (routing) costs involved. I’m going to round it up to 50ms for our example here. Where does that put us?

  • User clicks a button -> 50ms until it reaches the server
  • Server calculates response -> 100ms (fast)
  • Answer is returned -> again 50ms

This amounts to 200ms already, and we assumed a fast server response (no other requests in the queue, optimized DB query) and neglected any time the browser needs to actually update the DOM. As you can see, this simple example already flings us way beyond the “perceived as instant” limit of 100ms.

But here’s the twist: In many cases, we already know the outcome of a user action! And what’s more, we can trustingly assume that the action will succeed. Let’s see what we can make of this.

Starting Point

We start from a simple card with a “favorite” button. This button is enclosed in a <form> tag like would be the case when using Rails’ button_to helper:

https://stackblitz.com/edit/optimistic-ui-turbo-8?file=index.html%3AL98

After the button is clicked, the favorite state is switched on the server, and a <turbo-stream action="refresh"></turbo-stream> action is returned to reconcile the DOM. To visualize the effect of long latency even better, I have made the server response take 2 seconds:

https://stackblitz.com/edit/optimistic-ui-turbo-8?file=index.js%3AL31

A slowly updating favorite button

Challenge

The challenge this time is

Here’s the outcome:

A quickly updating favorite button

Caveat

The above will work only once, because due to a bug in Idiomorph, <template> tags aren’t morphed correctly. We have to prepend a separate turbo stream action for swapping out the template’s content with the inversed one manually: https://stackblitz.com/edit/optimistic-ui-turbo-8?file=index.js%3AL37. Don’t worry, I will detail that in the solution!

Teaser

  • How could you generalize this pattern?

More from

Turbo Drive - Swiper-like View Transitions
19 November 2024

Use the View Transitions API to drive powerful native-like animations

Turbo Drive - Use ULIDs for Optimistic UI
13 August 2024

Render deterministic optimistic UI elements using client-side ULIDs

Turbo Drive - Conditional InstantClick
13 February 2024

Conditionally opt out of Turbo Drive InstantClick using the Strategy pattern

Cookies
essential