بنقرة واحدة
hotwire-turbo
Best practices for using Hotwire Turbo to create reactive applications
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Best practices for using Hotwire Turbo to create reactive applications
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | hotwire-turbo |
| description | Best practices for using Hotwire Turbo to create reactive applications |
Rule updated on 12/15/2025 to Turbo version 8.0.18.
Hotwire consists of three main components, each suited for different use cases. Here's when to use each.
For full reference see https://turbo.hotwired.dev/
When to use:
How it works: Intercepts link clicks and form submissions, fetches the new page via AJAX, and swaps the <body> content while keeping the <head> intact.
Best practices:
data-turbo="false" to disable for specific links/forms (e.g., file downloads, external links)data-turbo-method="delete" for non-GET requests from links<%= link_to "Delete", invoice_path(@invoice), data: { turbo_method: :delete, turbo_confirm: "Are you sure?" } %>
When to use:
How it works: Instead of replacing the entire <body>, morphing intelligently diffs the current DOM against the new HTML and applies only the necessary changes. This preserves:
Enabling morphing:
<%# In your layout or page head %>
<meta name="turbo-refresh-method" content="morph">
<%# Optionally preserve scroll position %>
<meta name="turbo-refresh-scroll" content="preserve">
Per-element control:
<%# Keep an element from being morphed (preserves exact state) %>
<div data-turbo-permanent id="chat-messages">
<!-- Content preserved across page updates -->
</div>
When NOT to use morphing:
When to use:
How it works: Wraps a section of the page in a <turbo-frame> tag. When a link or form inside the frame is activated, only that frame's content is replaced.
Best practices:
<!-- index.html.erb -->
<%= turbo_frame_tag @invoice do %>
<div class="invoice-row">
<%= @invoice.number %>
<%= link_to "Edit", edit_invoice_path(@invoice) %>
</div>
<% end %>
<!-- edit.html.erb -->
<%= turbo_frame_tag @invoice do %>
<%= form_with model: @invoice do |f| %>
<!-- form fields -->
<% end %>
<% end %>
turbo_frame_tag with a model — Rails generates consistent IDs (invoice_123)data-turbo-frame="_top" for full-page navigationsrc and loading: "lazy":
<%= turbo_frame_tag "comments", src: comments_path, loading: "lazy" do %>
<p>Loading comments...</p>
<% end %>
data-turbo-frame="frame_id"When to use:
How it works: Returns <turbo-stream> elements that specify actions (append, prepend, replace, update, remove, before, after, morph, refresh) and target DOM elements by ID.
Best practices:
# Controller
def create
@invoice = current_user.invoices.build(invoice_params)
respond_to do |format|
if @invoice.save
format.turbo_stream # Renders create.turbo_stream.erb
format.html { redirect_to @invoice }
else
format.html { render :new, status: :unprocessable_entity }
end
end
end
<!-- create.turbo_stream.erb -->
<%= turbo_stream.prepend "invoices", @invoice %>
<%= turbo_stream.update "invoice_count", Invoice.count %>
<%= turbo_stream.remove "empty_state" %>
Stream Actions:
| Action | Description |
|---|---|
append | Add to end of target container |
prepend | Add to beginning of target container |
replace | Replace the entire target element |
update | Replace only the content (innerHTML) |
remove | Remove the target element |
before | Insert before the target |
after | Insert after the target |
morph | Morph the target element (intelligent diff) |
refresh | Trigger a full page refresh (optionally with morph) |
Morph stream action example:
<%# Smoothly update a section without replacing it entirely %>
<%= turbo_stream.morph "invoice_#{@invoice.id}", partial: "invoices/invoice", locals: { invoice: @invoice } %>
| Scenario | Solution |
|---|---|
| Standard navigation | Turbo Drive (automatic) |
| Edit form inline | Turbo Frame |
| Load section lazily | Turbo Frame with src |
| Add item to list | Turbo Stream append/prepend |
| Update multiple areas | Turbo Stream |
| Real-time via WebSocket | Turbo Stream over ActionCable |
| Delete from list | Turbo Stream remove |
| Modal/slideout | Turbo Frame targeting a container |
| Preserve scroll on refresh | Morphing with turbo-refresh |
| Smooth inline update | Turbo Stream morph |
| Update without losing focus | Morphing |
dom_id(@invoice)) for reliable targetinghtml format fallback for non-Turbo requests