hotwire

Infinite scrolling list using lazy Turbo Frames

Turbo Frames can implement infinite scrolling without a JS router. I render the first page normally and append a “next page” frame at the bottom with loading: :lazy. When the user scrolls and the frame enters view, Turbo fetches the next page automati

Render without layout for Turbo Frame requests

A classic Turbo foot-gun is returning a full layout inside a frame, which results in nested <html> and weird styling. The simplest fix is layout -> { turbo_frame_request? ? false : 'application' } at the controller level. I use this when I ha

Handle 401 responses in Turbo by forcing a full redirect

When a session expires, Turbo can end up swapping a login page into a frame, which is confusing. A practical fix is to detect 401 responses on the client and trigger a full-page visit (Turbo.visit) to the login URL. This keeps the app consistent and a

Stimulus outlets for inter-controller communication

Outlets allow Stimulus controllers to reference and communicate with other controller instances, enabling composition without tight coupling. I define outlets by specifying which controller types to connect to, and Stimulus automatically finds matchin

Build Turbo Stream responses in the controller (TagBuilder)

Most of the time I prefer *.turbo_stream.erb templates, but for small one-off responses it can be nice to generate streams directly in the controller using Turbo::Streams::TagBuilder. This keeps the logic close to the action and avoids creating a temp

Turbo Streams: inline “saved” indicator that updates on autosave

Users trust autosave when they can see it. I render a small #save_state region (“Saved just now”, “Saving…”, “Offline”) and update it via Turbo Streams. The autosave endpoint returns a stream that replaces the indicator, and optionally updates a hidde

Preview Active Storage uploads after attach using Turbo Streams

For image uploads, I like immediate previews. With Active Storage, you can render the preview server-side once the blob is attached, and use Turbo Streams to update the preview area. The form submits to an endpoint that attaches the blob and returns a

Morphing page updates with Turbo Morphing

Traditional Turbo Drive replaces the entire <body>, which can cause flickering and lose scroll position. Turbo Morphing (using idiomorph algorithm) intelligently diffs the DOM and updates only changed elements, preserving focus, scroll, and tran

Inline markdown preview using Turbo Frames

A markdown preview doesn’t need a client markdown parser. I render the preview server-side (same pipeline used in production), and load it into a Turbo Frame. The editor form includes a frame called preview, and a “Preview” button submits the form to

Autosave drafts with Stimulus + Turbo (lightweight)

For long text entry, autosave is a huge quality-of-life improvement. I implement it with a Stimulus controller that debounces input and submits the form to a drafts endpoint in the background. The response is a turbo stream that updates a “Saved at …”

Add/remove nested fields with Stimulus (no cocoon)

Nested fields are a common Rails pain point, and the old solution was heavy JS gems. With Stimulus, I keep it minimal: render a hidden <template> containing the fields with a placeholder index, then on “Add” clone it and swap the placeholder for

Turbo Frames modal: load, submit, then close via stream

A modal is just a frame boundary. Load the modal content into a dedicated frame, then on submit broadcast/stream a close action plus a list update. You get “SPA modal UX” without a frontend router.