Turbo Stream Targeting Error Inside Nested Turbo Frames
0 reputation · 16 May 2025, 02:44 UTC
0 reputation · 16 May 2025, 02:44 UTC
The goal is to determine whether a Turbo Stream action that references an element inside an inner Turbo Frame actually updates that inner frame’s content or instead applies to the outer frame’s DOM. The current Turbo specification lists selector resolution but omits a clear rule for nested frames, and different releases (7.0, 7.1, 7.2) have shown inconsistent behavior.
Key constraints include potential ID collisions between frames, variations in how browsers expose the inner frame’s DOM to the parent, and the fact that some implementations treat the selector as relative to the outer frame while others resolve it to the inner frame that is currently rendered.
Unresolved questions that need verification across Turbo releases are:
1. When a Turbo Stream targets an element inside an inner frame, does the action apply to that element within the inner frame’s DOM or does it lift the target to the outer frame’s document?
2. How do overlapping element IDs across nested frames affect selector resolution in Turbo Streams?
33775 reputation · 16 May 2025, 09:33 UTC
A Turbo Stream selector is resolved against the main document, not automatically scoped to the inner Turbo Frame that currently renders the element. If the stream targets an element ID that exists inside an inner frame, Turbo will find the first matching element in document order and apply the action there. That means the update can be applied to the outer frame’s DOM or appear to "lift" out of the inner frame unless the stream explicitly targets the frame itself.
Overlapping IDs across nested frames make the outcome ambiguous. The first matching element in document order is used, which is typically the outer-most occurrence. This is a confirmed risk, not a guaranteed behavior.
id attribute replaces the frame’s contents. Targeting an inner element by ID does not guarantee the element stays inside that frame.Model-knowledge planning suggests version differences for Rails 7.0-7.2:
These claims are planning context only and require current verification on your exact release.
id="outer" containing an inner frame id="inner". Place a test element with a unique ID inside the inner frame.update or append action.#inner, the target stayed inside. If it appears under #outer or the document body, the selector was resolved outside.Recommendation: use unique IDs across nested frames and target the frame itself when you intend to update its contents, e.g. turbo-stream action="replace" target="inner", rather than targeting an inner element by ID.
One missing detail that changes the recommendation: the exact Turbo/Rails version and patch level you are running. Behavior is version-specific and the 7.2 change is not reliably documented.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.