35+ Years Experience Netherlands Based ⚡ Fast Response Times Ruby on Rails Experts AI-Powered Development Fixed Pricing Available Senior Architects Dutch & English 35+ Years Experience Netherlands Based ⚡ Fast Response Times Ruby on Rails Experts AI-Powered Development Fixed Pricing Available Senior Architects Dutch & English
Rails Turbo Frames: Dynamische UI's Bouwen Zonder JavaScript

Rails Turbo Frames: Dynamische UI's Bouwen Zonder JavaScript

roger
ruby-on-rails
Hoe je Turbo Frames in Rails 8 gebruikt voor snelle, dynamische interfaces met lazy loading, inline editing en frame-navigatie — zonder custom JavaScript.

Turbo Frames splitsen een pagina op in onafhankelijke secties die laden en updaten zonder volledige pagina-herladingen. Je krijgt de responsiviteit van een single-page app met server-gerenderde HTML. Geen React. Geen webpack-gedoe. Gewoon Rails views en een paar HTML-attributen.

Zo ziet een Turbo Frame eruit in de praktijk:

<%%= turbo_frame_tag "user_profile" do %>
  <h2><%%= @user.name %></h2>
  <p><%%= @user.bio %></p>
  <%%= link_to "Bewerken", edit_user_path(@user) %>
<%% end %>

Als een gebruiker op “Bewerken” klikt, vervangt Rails alleen de content binnen dat frame — de rest van de pagina blijft staan. De browser herlaadt niet. De server rendert een volledig HTML-antwoord, maar Turbo haalt er alleen het matchende frame uit.

Hoe Frame Matching Werkt

Turbo Frames gebruiken een id-attribuut om content te matchen tussen de huidige pagina en het serverantwoord. Wanneer je op een link klikt of een formulier verstuurt binnen een frame:

  1. Turbo stuurt een standaard HTTP-request naar de server
  2. Ontvangt een volledig HTML-antwoord
  3. Zoekt de <turbo-frame> met het matchende id in het antwoord
  4. Vervangt de content van het huidige frame met het response-frame

Je controller hoeft niets te weten over Turbo. Die rendert gewoon een normale view. De magie gebeurt client-side via HTML-attribuut matching.

# app/controllers/users_controller.rb
def edit
  @user = User.find(params[:id])
  # Niets bijzonders — dezelfde controller action als altijd
end
<%# app/views/users/edit.html.erb %>
<%%= turbo_frame_tag "user_profile" do %>
  <%%= form_with model: @user do |f| %>
    <%%= f.text_field :name %>
    <%%= f.text_area :bio %>
    <%%= f.submit "Opslaan" %>
  <%% end %>
<%% end %>

Na het versturen van het formulier verwerkt Rails de update en rendert opnieuw de show- of edit-view. Turbo vervangt de frame-content. De URL in de browser verandert standaard niet — dat is bewust zo voor inline edits.

Lazy Loading van Frames

Frames kunnen hun content laden na de initiële pagina-render. Handig voor zware queries, data van derden of secties onder de vouw.

<%%= turbo_frame_tag "recent_activity", src: user_activity_path(@user), loading: :lazy do %>
  <p>Activiteit laden...</p>
<%% end %>

Het loading: :lazy attribuut vertelt Turbo om de frame-content pas op te halen wanneer het zichtbaar wordt in de viewport. Zonder dit attribuut haalt Turbo het direct op na page load. De placeholder-content (“Activiteit laden…”) wordt getoond tot het antwoord binnenkomt.

Ik heb lazy frames gebruikt op een dashboard dat analytics ophaalde van drie verschillende services. De initiële laadtijd ging van 2,8 seconden naar 600ms. Elk analytics-paneel laadde onafhankelijk terwijl de gebruiker naar beneden scrollde.

Uit het Frame Breken

Standaard navigeren links binnen een Turbo Frame binnen dat frame. Soms moet een link het volledige pagina navigeren. Gebruik data-turbo-frame="_top":

<%%= turbo_frame_tag "search_results" do %>
  <%% @results.each do |result| %>
    <%%= link_to result.title, result_path(result), data: { turbo_frame: "_top" } %>
  <%% end %>
<%% end %>

Dit is het patroon dat ik gebruik bij zoekinterfaces. Het zoekformulier en de resultaten zitten in een frame voor instant filtering, maar een klik op een resultaat laadt de volledige detailpagina.

Een Ander Frame Targeten

Links en formulieren kunnen een ander frame targeten dan waar ze in zitten. Dit maakt patronen als tabbed interfaces en master-detail layouts mogelijk:

<nav>
  <%%= link_to "Profiel", user_profile_path, data: { turbo_frame: "main_content" } %>
  <%%= link_to "Instellingen", user_settings_path, data: { turbo_frame: "main_content" } %>
  <%%= link_to "Facturatie", user_billing_path, data: { turbo_frame: "main_content" } %>
</nav>

<%%= turbo_frame_tag "main_content" do %>
  <%%= render "profile" %>
<%% end %>

Inline Editing Patroon

Waarschijnlijk de meest voorkomende Turbo Frame use case. Toon een read-only view, klik op bewerken, wissel naar een formulier, verstuur, wissel terug naar read-only.

<%# app/views/comments/_comment.html.erb %>
<%%= turbo_frame_tag dom_id(comment) do %>
  <div class="comment">
    <p><%%= comment.body %></p>
    <%%= link_to "Bewerken", edit_comment_path(comment) %>
  </div>
<%% end %>

De status: :unprocessable_entity (422) bij validatiefouten is cruciaal in Rails 8. Turbo verwacht dat mislukte form-submissions 422 retourneren, niet 200. Als je 200 retourneert bij een mislukt formulier, behandelt Turbo het als succes en ziet de gebruiker geen validatiefouten. Dit kostte me uren de eerste keer.

Turbo Frames vs Turbo Streams

Frames vervangen één rechthoekige sectie van de pagina. Streams kunnen meerdere delen tegelijk updaten. Gebruik frames wanneer:

  • Je één afgebakende sectie bijwerkt
  • De interactie een request-response patroon volgt
  • Je de eenvoud van standaard controller actions wilt

Gebruik Turbo Streams wanneer een actie meerdere ongerelateerde pagina-onderdelen moet bijwerken.

In productie begin ik altijd met frames en stap ik alleen over op streams wanneer de UI multi-region updates vereist. Frames dekken 80% van de dynamische UI-behoeften met half de complexiteit.

Performance Overwegingen

Turbo Frames maken extra HTTP-requests. Elk frame met een src-attribuut is een aparte round trip.

Beperk dit met:

Russian doll caching — Cache frame-responses agressief. Omdat frames partial views renderen, werkt Rails fragment caching hier perfect.

Conditioneel laden — Voeg alleen src toe aan frames die de gebruiker daadwerkelijk ziet.

Response-grootte — Frame-responses moeten lean zijn. Gebruik een layout zonder navigatie en footer.

Veelgemaakte Fouten

Vergeten van het matchende frame ID. Als je response geen turbo-frame bevat met hetzelfde ID, logt Turbo een foutmelding en wordt het frame leeg.

200 gebruiken voor validatiefouten. Retourneer status: :unprocessable_entity voor mislukte form-submissions.

Frames nesten zonder nadenken. Links in een inner frame targeten standaard dat inner frame. Gebruik expliciete data-turbo-frame attributen.

Veelgestelde Vragen

Wanneer moet je Turbo Frames gebruiken?

Turbo Frames werken het best voor interacties die één paginasectie bijwerken: inline editing, tabbed content, zoekfilters met directe resultaten en lazy-loaded panelen.

Werken Turbo Frames met Rails API-only mode?

Nee. Turbo Frames vereisen server-gerenderde HTML-responses. API-only Rails apps die JSON retourneren kunnen geen Turbo Frames gebruiken.

Kan je Turbo Frames gebruiken met Devise?

Ja, maar let op redirect-gedrag. Devise redirects voor niet-geauthenticeerde requests kunnen in een frame terechtkomen. Gebruik data-turbo-frame="_top" op Devise-beschermde links.

Hoe beïnvloeden Turbo Frames SEO?

Content in lazy-loaded frames staat niet in de initiële HTML-response. Voor SEO-kritische content, render het in de initiële paginalading in plaats van in een lazy frame.

#rails #hotwire #turbo #turbo-frames #frontend
r

About the Author

Roger Heykoop is een senior Ruby on Rails ontwikkelaar met 19+ jaar Rails ervaring en 35+ jaar ervaring in softwareontwikkeling. Hij is gespecialiseerd in Rails modernisering, performance optimalisatie, en AI-ondersteunde ontwikkeling.

Get in Touch

Share this article

Need Expert Rails Development?

Let's discuss how we can help you build or modernize your Rails application with 19+ years of expertise

Schedule a Free Consultation