hotwire

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

Stimulus: copy-to-clipboard with fallback + selection

Copy buttons are deceptively tricky across browsers. This Stimulus controller uses the Clipboard API when available, falls back to execCommand, and provides a hook for “Copied!” UI.

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

Morphing page refreshes with turbo_refreshes_with

When a page has lots of dynamic pieces but I still want “just refresh it” semantics, I use Turbo’s morphing refreshes. With turbo_refreshes_with method: :morph, Turbo updates the DOM by morphing rather than doing a full replace, which tends to preserv

Turbo Frames: Inline edit that swaps form <-> row

Inline editing works best when the frame boundary is small and stable (one row). Render the display state inside a frame, then link to edit inside the same frame. Submit swaps it back. This keeps controllers simple and UI snappy.

Broadcast job progress updates to a Turbo Frame

Long-running jobs are where Hotwire can feel magical: start an export, then watch progress update live. I give each job a “progress” model, render it in a turbo_frame_tag, and broadcast replacements as the job advances. The job updates percent and sta

ActionCable channel that streams Turbo updates safely

Even with model broadcasts, it’s useful to know how streams map to ActionCable channels. Turbo::StreamsChannel is essentially a channel that streams from a signed stream name. When I need custom behavior, I still follow the same scoping rules: identif

ETag + last_modified for expensive Turbo Frame endpoints

Turbo Frames can trigger lots of small requests, so caching matters. For expensive frame endpoints (like an activity panel), I use stale? with an ETag that includes a cache key and the latest update timestamp. If the content hasn’t changed, Rails retu

Broadcasts refreshes for complex pages (less target wiring)

When a page has many small targets, wiring dozens of Turbo Stream operations can get noisy. Rails’ broadcasts_refreshes (Rails 7.1+) lets you take a pragmatic approach: broadcast a refresh, and Turbo morphs the page. It’s not always the right choice (