Turbo-Location header: redirect a frame submission to a new URL

When a form submits inside a Turbo Frame, a normal redirect can sometimes feel odd (especially if the redirect response doesn’t include the matching frame). A clean approach is to set the Turbo-Location header for Turbo requests. Turbo interprets it a

Undo delete with a Turbo Stream “restore” action

Undo is a great UX improvement for destructive actions. My approach is: on destroy, soft-delete the record (or keep enough data to restore), remove it from the list via turbo_stream.remove, and append a toast with an “Undo” link. Clicking “Undo” hits

Use dom_id everywhere to keep Turbo replacements deterministic

Turbo Stream updates are easiest when every meaningful element has a stable id. Rails’ dom_id helper makes this painless: dom_id(@post) yields post_123, and dom_id(@post, :header) yields header_post_123. I use this pattern throughout Hotwire UIs so I

Inline create form that prepends into a list with Turbo Streams

My favorite Hotwire demo is the classic “inline create” on an index page. The form sits at the top of the page. When submitted, the create action returns turbo streams that (1) prepend the new item into the list and (2) replace the form with a fresh,

Scroll into view after append using a custom Turbo Stream action

When appending new content (like a new message), I sometimes want to scroll it into view automatically. Rather than adding JS in the controller, I use a custom turbo stream action scroll_into_view that finds the target element and calls scrollIntoView

Typing indicator via ActionCable + Turbo Streams

Typing indicators can be done without a complex protocol. I broadcast a small turbo stream replace to a typing_indicator target when a user starts typing, and another replace to clear it after a timeout. On the client, a Stimulus controller sends “typ

Custom confirm dialog with Stimulus (better than window.confirm)

data-turbo-confirm uses the browser confirm dialog, which is functional but not pretty. For a more polished app, I replace it with a Stimulus controller that intercepts clicks, shows a custom modal, and only proceeds if the user confirms. Turbo makes

Frame navigation that targets a specific frame via form_with

Sometimes a form submission should update a specific section rather than navigate the whole page. With Turbo, this is as easy as setting data-turbo-frame on the form. For example, a filter form can target a results frame, so submissions replace only t

Fragment caching inside Turbo Frames (fast lists)

Hotwire doesn’t replace caching—it makes it more valuable because you’re sending HTML frequently. I use fragment caching inside list partials and keep cache keys stable with cache blocks. The pattern is: cache each row by record, and cache the list wr

Lazy-load heavy panels with IntersectionObserver + Turbo frame

Not every part of a page needs to load immediately. For heavy panels (analytics charts, audit logs), I use a Turbo Frame with src and a tiny Stimulus controller that sets the src when the element becomes visible via IntersectionObserver. This avoids f

Admin “quick toggle” with Turbo Streams and a single partial

Admin toggles (published/unpublished, featured/unfeatured) are a perfect Hotwire use case: server-rendered state, instant UI update. I render the toggle as a partial inside a frame, and the update action responds with a turbo stream replacing that fra

Scoped navigation inside a sidebar with Turbo Frames

Sometimes you want only part of the screen to navigate—like a sidebar list updating the main content. Turbo Frames can do this cleanly: render the sidebar normally, and make its links target a turbo_frame_tag called main. Clicking a link swaps the mai