Introduction
By default, links inside a Turbo Frame only update that frame. Turbo provides targeting controls to direct navigation to any frame or break out entirely for full-page navigation.
Key Concepts
- Frame Scoping: Links inside a frame automatically target that frame.
data-turbo-frame: Overrides the default frame target on links/forms._topTarget: Special value for full-page navigation, escaping frame scope.- Frame
targetattribute: Default target for all links inside a frame.
Real World Context
Frame targeting enables tabbed interfaces, sidebar navigation updating a main area, and search forms updating result lists — all without JavaScript.
Deep Dive
Default Scoping
erb<%= turbo_frame_tag "task_42" do %> <p>Buy groceries</p> <%= link_to "Edit", edit_task_path(42) %> <!-- updates only task_42 --> <% end %>
Clicking Edit replaces only this frame. Everything else stays untouched.
Cross-Frame Targeting
Links can target any frame by ID:
erb<nav> <%= link_to "Overview", product_overview_path(@product), data: { turbo_frame: "tab_content" } %> <%= link_to "Reviews", product_reviews_path(@product), data: { turbo_frame: "tab_content" } %> </nav> <%= turbo_frame_tag "tab_content" do %> <%= render "overview" %> <% end %>
Tab links outside the frame target it by ID, creating a tabbed interface with zero JavaScript.
Default Target on Frame
Set a default target for all links in a frame:
erb<%= turbo_frame_tag "sidebar", target: "main_content" do %> <ul> <li><%= link_to "Dashboard", dashboard_path %></li> <li><%= link_to "Settings", settings_path %></li> </ul> <% end %> <%= turbo_frame_tag "main_content" do %> <%= yield %> <% end %>
Every link in the sidebar updates main_content without per-link attributes.
URL Updates
Frame navigations don't update the browser URL by default. Add turbo_action for bookmarkable URLs:
erb<%= link_to "Electronics", products_path(category: "electronics"), data: { turbo_frame: "product_list", turbo_action: "advance" } %>
Common Pitfalls
- Unintended frame scoping — Links inside frames only update that frame. Use
_topwhen you want full-page navigation. - Missing frame in response — If the targeted frame doesn't exist in the response, Turbo shows a Content Missing error.
Best Practices
- Use
targeton the frame element — When all links should navigate the same target, set it on the frame. - Add
turbo_action: "advance"for bookmarkable navigations — Tab selections, filters, and pagination should update the URL.
Summary
- Links inside frames automatically scope to that frame.
data-turbo-frame="_top"breaks out for full-page navigation.- Links can target any frame by specifying its ID.
- The
targetattribute on a frame sets a default for all its links. data-turbo-action="advance"updates the browser URL.
Code Examples
ruby
# A tabbed interface — zero JavaScript
# <nav>
# <%= link_to "Details", product_details_path(@product),
# data: { turbo_frame: "tab_panel", turbo_action: "advance" } %>
# <%= link_to "Reviews", product_reviews_path(@product),
# data: { turbo_frame: "tab_panel", turbo_action: "advance" } %>
# </nav>
# <%= turbo_frame_tag "tab_panel" do %>
# <%= render "details" %>
# <% end %>