agentsclimarketplace

Turbo frames patterns

Skill davidteren/hotwire-codex-skills/skills/turbo-frames-patterns

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).From its SKILL.md

Install
npx -y skills add davidteren/hotwire-codex-skills --skill turbo-frames-patterns

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things 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.
  • runs commandsInstructs the agent to run 1 command, including `scripts/lint_turbo_frames.sh path/to/rails-app`.

SKILL.md

3.4 KB, 738 tokens by cl100k_base, 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)

  1. Target must resolve — a link targeting turbo_frame: "x" needs a turbo_frame_tag "x" in the response (and your views), or the click silently does nothing. Use _top to break out to a full-page navigation (the common case for row links). (linted)
  2. Collection partials use dom_id(record) — a literal turbo_frame_tag "card" in a per-row partial stamps the same id on every row → duplicate DOM ids, only the first updates. (linted)
  3. Frame request variant — render the lean show.html+turbo_frame.erb for frame requests (turbo_frame_request?) instead of re-rendering the whole layout.
  4. turbo_action: "advance" — frame navigations don't change the URL by default; promote tab/list/filter frames so reload/back/forward work.
  5. Filter/search forms go OUTSIDE the frame they target — a form inside the frame replaces itself (and the focused input) on every submit.
  6. Lazy framessrc: + loading: :lazy defer content; the src response 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.

What ships with it: 2 files

12.2 KB alongside SKILL.md, 1 of them executable

references/

scripts/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.