Turbo frames patterns
Skill davidteren/hotwire-codex-skills/skills/turbo-frames-patterns
Unofficial Claude Code skillset inspired by The Rails and Hotwire Codex — 8 skills for building interactive Rails + Hotwire apps (Turbo, Stimulus, Hotwire Native) across web, iOS & Android, each with a runnable checker.
npx -y skills add davidteren/hotwire-codex-skills --skill turbo-frames-patternsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Scope navigation to a region with Turbo Frames correctly, and catch the wiring mistakes that fail silently. Use when adding a turbo_frame_tag (a turbo-frame element), driving a frame from an outside link/form, lazy-loading a panel (src + loading: :lazy), inline-editing a row, or debugging a frame that does nothing / a click that navigates nowhere / a filter form that loses focus / duplicate frame ids from a collection. The region-scoped complement to targeted streams (turbo-streams-patterns) and morph refreshes (turbo-morphing).
SKILL.md
3.4 KB, as published. Nobody here has run it
Turbo Frames
Frames scope navigation to a region: a click or form submit inside a <turbo-frame> is
captured by Turbo and only that frame updates. The failures are quiet — a mistargeted or
missing frame produces no error, just navigation that goes nowhere. Full patterns:
references/turbo-frames-guide.md.
When to use
- Adding a frame (
turbo_frame_tag "id"/<turbo-frame id="id">). - Driving a frame from outside (
data: { turbo_frame: "id" }) — e.g. a filter bar above a list. - Lazy-loading a panel (
src:+loading: :lazy). - Inline-editing one record (a per-row
turbo_frame_tag dom_id(record)). - Debugging: a frame that does nothing, a click that navigates nowhere, a filter form that loses focus on each keystroke, or duplicate ids from a collection partial.
The patterns (and their footguns)
- Target must resolve — a link targeting
turbo_frame: "x"needs aturbo_frame_tag "x"in the response (and your views), or the click silently does nothing. Use_topto break out to a full-page navigation (the common case for row links). (linted) - Collection partials use
dom_id(record)— a literalturbo_frame_tag "card"in a per-row partial stamps the same id on every row → duplicate DOM ids, only the first updates. (linted) - Frame request variant — render the lean
show.html+turbo_frame.erbfor frame requests (turbo_frame_request?) instead of re-rendering the whole layout. turbo_action: "advance"— frame navigations don't change the URL by default; promote tab/list/filter frames so reload/back/forward work.- Filter/search forms go OUTSIDE the frame they target — a form inside the frame replaces itself (and the focused input) on every submit.
- Lazy frames —
src:+loading: :lazydefer content; thesrcresponse must contain a matching<turbo-frame id>or the frame stays empty.
Patterns 3–6 aren't checker-able with low false positives — see the reference.
Lint an app
scripts/lint_turbo_frames.sh path/to/rails-app
Flags (HIGH confidence, literal ids only): a dangling frame target — a link/form
targets a frame id with no turbo_frame_tag / <turbo-frame id> defined in any view
(navigation goes nowhere); a literal frame id inside a collection partial — duplicate
DOM ids (use dom_id). Reserved targets (_top/_self) and dynamic ids
(dom_id(...), interpolation, <%= %>) are never flagged — when either side is dynamic
it can't be resolved statically, so it's skipped and reported as such. Heuristic regex
scan (needs ruby), not an ERB/HTML parser — names its ceiling. Verified: clean on
miela_app (6 real frames, all targets resolve, collection partials use dom_id), flags a
synthetic dangling-target + duplicate-id app.