turbo

Broadcast a status badge update on background processing

A lot of Rails apps have records that transition through states: queued, processing, done. With Hotwire, I render a status badge partial and broadcast replacements when the state changes. A background job updates the record, and the model broadcasts a

Stimulus: debounced search that plays nicely with Turbo

Client-side debounce is best done in Stimulus (not in view helpers). This controller submits the nearest form after a short pause, while letting Turbo handle the navigation and frame replacement.

Customize Turbo progress bar styling with Tailwind/CSS

Turbo includes a progress bar at the top of the page, and it’s a surprisingly visible part of perceived quality. I like to set the color and height to match the app’s brand. This is pure CSS: target .turbo-progress-bar. You can also make it slightly t

Keep navbar state across Turbo navigations with data-turbo-permanent

Some UI elements should survive navigation: a music player, a search input, or a navbar with an open dropdown. Turbo’s data-turbo-permanent lets you mark a DOM node that shouldn’t be replaced during visits. I use it carefully—permanent nodes can keep

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,

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

Turbo Frames: inline “details drawer” without a SPA router

A common UI is a list on the left and a details panel (drawer) on the right. With Turbo Frames, each list item link can target a details frame. Clicking an item swaps the drawer content while leaving the list intact. The server still renders HTML, so

Inline form validation feedback via Turbo Streams

When forms live inside a Turbo Frame (modal or inline edit), validation needs to feel immediate without a full-page refresh. I render the form inside a frame with an ID like post_form. On submit, create/update returns status: :unprocessable_entity and

Turbo Streams: partial replace with morphing (less jitter)

When replacing DOM chunks, morphing reduces flicker and preserves focus/selection. If you enable morphing, prefer server-rendered HTML that’s stable and keyed. It’s a subtle but meaningful quality improvement.

Per-account stream scoping to prevent “cross-tenant” updates

Broadcasting is powerful, but it’s also easy to accidentally leak updates if everyone subscribes to a global stream. My default is to scope streams to a tenant boundary (like Current.account) and a resource. That means turbo_stream_from [current_accou

Use data-turbo-action to control history (advance vs replace)

Turbo Drive records visits in browser history. For some interactions (like typing through search results), you don’t want every click to create a new history entry. Turbo supports data-turbo-action='replace' to replace the current history entry instea

Custom turbo_stream action tag: highlight an updated element

Turbo gives you a handful of built-in stream actions (append, replace, remove), but sometimes you want behavior like “replace then highlight”. You can implement this as a custom action: send a turbo-stream with action='highlight' and include a templat