How to Use Hotwire in Rails: Quick Guide with Examples
To use
Hotwire in Rails, add the hotwire-rails gem and run its installer to set up Turbo and Stimulus. Then use Turbo Frames and Turbo Streams in your views to update parts of the page dynamically without full reloads.Syntax
Hotwire in Rails mainly uses Turbo Frames and Turbo Streams to update HTML dynamically. Turbo Frames wrap parts of your page with <turbo-frame> tags to isolate updates. Turbo Streams use <turbo-stream> tags to send real-time updates from the server.
Stimulus controllers add JavaScript behavior with simple HTML attributes like data-controller.
html
<turbo-frame id="frame_id"> <!-- Content that can be updated independently --> </turbo-frame> <turbo-stream action="replace" target="frame_id"> <template> <!-- New content to replace inside the frame --> </template> </turbo-stream>
Output
A part of the page inside the turbo-frame updates without reloading the whole page.
Example
This example shows a simple Rails setup using Hotwire to update a list of messages without reloading the page. When a new message is created, Turbo Streams update the list automatically.
ruby+erb
# Gemfile gem 'hotwire-rails' # Run in terminal bundle install rails hotwire:install # app/controllers/messages_controller.rb class MessagesController < ApplicationController def index @messages = Message.all end def create @message = Message.new(message_params) if @message.save respond_to do |format| format.html { redirect_to messages_path } format.turbo_stream end else render :index end end private def message_params params.require(:message).permit(:content) end end # app/views/messages/index.html.erb <h1>Messages</h1> <%= form_with model: Message.new, local: false do |form| %> <%= form.text_field :content, placeholder: "Type a message" %> <%= form.submit "Send" %> <% end %> <turbo-frame id="messages"> <%= render @messages %> </turbo-frame> # app/views/messages/_message.html.erb <p><%= message.content %></p> # app/views/messages/create.turbo_stream.erb <turbo-stream action="append" target="messages"> <template> <%= render @message %> </template> </turbo-stream>
Output
A page with a message input form and a list. When you submit a message, it appears instantly below without reloading the page.
Common Pitfalls
- Not running
rails hotwire:installafter adding the gem causes missing JavaScript setup. - Using
form_withwithlocal: truedisables Turbo, so dynamic updates won't work. - Forgetting to wrap dynamic content in
<turbo-frame>or target the correct frame in Turbo Streams leads to no visible updates. - Not responding with
format.turbo_streamin controller actions prevents Turbo Streams from working.
erb
# Wrong: form disables Turbo <%= form_with model: @message, local: true do |form| %> ... <% end %> # Right: enable Turbo <%= form_with model: @message, local: false do |form| %> ... <% end %>
Quick Reference
- Turbo Frames: Use
<turbo-frame id="frame_id">to isolate page parts. - Turbo Streams: Use
<turbo-stream action="replace" target="frame_id">to update frames. - form_with: Use
local: falseto enable Turbo form submission. - Install: Add
gem 'hotwire-rails'and runrails hotwire:install.
Key Takeaways
Add the hotwire-rails gem and run rails hotwire:install to set up Turbo and Stimulus.
Use to isolate parts of your page for dynamic updates.
Respond with format.turbo_stream in controllers to send Turbo Stream updates.
Use form_with with local: false to enable Turbo-powered form submissions.
Wrap dynamic content properly and target frames correctly to see updates without full page reloads.