Implementing Partial Page Updates with Turbo Frames
Learn how to use Turbo Frames to implement partial page updates, reducing server overhead and eliminating the need for complex client-side state management.
24 Feb 2026, 23:04 UTC

The Problem: State Synchronization Overhead
Modern web applications often struggle with the trade-off between full-page reloads, which are slow and destroy client-side state (like scroll position or input focus), and complex Single Page Application (SPA) architectures that require duplicating state management on both the client and server.
The goal is to update a specific section of a page—such as a comment thread or a filtered product list—without reloading the entire document or writing custom JavaScript to handle JSON responses and DOM manipulation.
The Design: Scoped HTML Replacement
Turbo Frames solve this by treating specific DOM elements as independent navigation targets. Instead of the server sending JSON that a client-side framework must render, the server sends a raw HTML fragment. Turbo intercepts the request and swaps the content of the frame with the matching fragment from the response.
Requirements for Implementation
- Matching IDs: The server response must contain a
<turbo-frame>element with an ID that exactly matches the ID of the frame on the current page. - Fragment Responses: To optimize bandwidth, the server should omit the global layout (header, footer, navigation) when responding to a Turbo Frame request.
- Standard HTML: The interaction relies on standard
<a>tags and<form>elements.
Smallest Suitable Design Example
Consider a user profile page where only the "Bio" section needs to be editable without refreshing the rest of the profile.
Initial Page State:
<!-- The browser renders this initially -->
<div class="profile-container">
<h1>User Profile</h1>
<turbo-frame id="bio_section">
<p>This is the user's current bio.</p>
<a href="/profile/bio/edit">Edit Bio</a>
</turbo-frame>
<div class="other-content">Static profile data...</div>
</div>
Server Response for /profile/bio/edit:
<!-- The server returns only this fragment -->
<turbo-frame id="bio_section">
<form action="/profile/bio/update" method="post">
<textarea name="bio">This is the user's current bio.</textarea>
<button type="submit">Save</button>
<a href="/profile">Cancel</a>
</form>
</turbo-frame>
Trust and Data Boundaries
Turbo Frames operate over standard HTTP. Because they use fetch requests under the hood, they inherit the security context of the browser:
- Authentication: Session cookies are sent automatically with the request.
- CSRF Protection: Forms within Turbo Frames must still include CSRF (Cross-Site Request Forgery) tokens, as they perform standard POST/PATCH/DELETE requests.
- Scope: Navigation is scoped. A link inside a frame targets that frame by default. To break out of a frame and navigate the entire page, use
data-turbo-frame="_top".
Operational Checks and Verification
To verify that a Turbo Frame is functioning correctly and not accidentally triggering a full page reload, perform the following checks:
| Check | Method | Expected Result |
|---|---|---|
| Network Payload | Browser DevTools > Network Tab | The response body contains only the <turbo-frame> and its children, not the full <html> document. |
| DOM Stability | Inspect Element | Only the inner HTML of the target frame changes; the surrounding page elements remain untouched. |
| Browser History | URL Bar | The URL does not change unless data-turbo-action="advance" is explicitly used. |
Failure Modes and Design Shifts
Certain conditions render Turbo Frames unsuitable, requiring a shift in architecture:
- Nested Frame Complexity: Deeply nesting frames can lead to "zombie" content where the inner frame updates but the outer frame's state becomes stale. If multiple sections of the page must update simultaneously, use Turbo Streams instead of Frames.
- URL-Driven State: If the user needs to be able to bookmark the specific state of the frame (e.g., a specific tab in a tabbed interface), you must implement
data-turbo-action="advance"to push the change to the browser history. - Heavy Client-Side Logic: If the update requires immediate, high-frequency UI feedback (like a drag-and-drop interface), the server-roundtrip latency of Turbo Frames will be too high; a client-side state manager (like Stimulus or a JS framework) is required.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.