turbo

Turbo Streams: broadcast from a job for long operations

For long operations (imports, conversions), run work in a job and stream progress updates. The job emits broadcast_update_to so the UI updates live without polling.

Turbo Streams: partial page auth failure handling

When a session expires, Turbo requests can start returning 401/302 and the UI gets confusing. Handle unauthorized turbo requests explicitly: return a stream that updates a “session expired” banner or triggers a redirect.

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

Keyboard shortcut “command palette” modal (Hotwire-first)

A command palette feels like a SPA feature, but you can do it Hotwire-first: place a turbo_frame_tag 'modal' in the layout and load the palette HTML into it. A small Stimulus controller listens for meta+k and navigates the modal frame to /palette. The

Use 303 See Other after POST in Turbo flows

After a POST, Turbo behaves best when you redirect with 303 See Other (Rails symbol :see_other). This avoids the browser trying to re-submit the POST when the user refreshes, and it plays nicely with Turbo Drive’s navigation semantics. I use it especi

Attach custom headers to Turbo fetch requests (stimulus-free)

Sometimes you need to attach a header to every Turbo request (like a feature-flag variant, or a client version). Turbo emits turbo:before-fetch-request, which lets you mutate the outgoing request before it is sent. I keep the handler tiny and global (

Update an error summary area via turbo_stream.update

For forms with multiple fields, I like an error summary at the top. With Turbo Streams, you can update just the summary target when validation fails. This is helpful when the form is long and the user might not see inline errors immediately. The serve

Server-rendered skeleton UI for slow frames

For slow endpoints, I like a skeleton placeholder rather than a blank area. Turbo Frames make this easy: render a “loading skeleton” inside the frame tag as the initial content, then set src so Turbo fetches the real content. When the response arrives

Turbo-friendly 422 responses for invalid forms

In a Turbo app, returning the right HTTP status is not optional—it controls how Turbo treats the response. For invalid form submissions, return 422 Unprocessable Entity and render the form with errors. If you mistakenly return 200, Turbo may treat it

Pagination links that escape a Turbo Frame with _top

Sometimes a frame is great for partial navigation, but sometimes you explicitly want a full-page visit. Pagination is a common case: when the page number changes, I often want the URL to update and the browser history to behave normally. You can tell

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

Multi-step wizard navigation with Turbo Frames

Wizards are often over-engineered with client state machines. With Turbo Frames, I render each step inside a frame, and the “Next” button simply POSTs to update the record and then redirects to the next step URL. If validation fails, I re-render the s