David Boureau

Web developer & teacher @saaslit

The simplest turbo-frame example

Turbo frame is a powerful feature of Hotwire, here is a quick memo about how to follow conventions in the simplest case. Convention over configuration is powerful, but sometimes it is also a problem when you are not sure anymore about conventions ;) so I plan to release more "simplest *** Hotwire feature".

What is a turbo frame ?

A turbo frame is a node of the DOM that is able to be replaced by another, without refreshing the browser (when the user clicks on a button for example).

Think about the old days where you had to update the DOM through an ajax request (without a full page reload).

Unexplained (but short) answer

For those who already knows a little about Rails and Hotwire, and just want a quick check about syntax, here is the full (unexplained) answer :

# inside config/routes.rb
  post "full_list", to: "welcome#full_list"
# inside app/controllers/welcome_controller.rb
class WelcomeController < DashboardController

  def full_list

<!-- inside app/views/welcome/index.html.erb -->
<turbo-frame id="view_more">
  <%= button_to "View all", full_list_path %>
<!-- inside app/views/welcome/full_list.html.erb -->
<turbo-frame id="view_more">
    That's all! Nothing else to show.

A little bit of context

Rails is well known for it's "convention over configuration" paradigm. With simpler words, it means "as long as you follow naming conventions, everything works".

When discovering new features like Turbo and Hotwire, "everything works" usually starts by "everything is buggy"

So I decided to put this article as a reference for people who begins with Turbo Frame.

The bare minimum conventions not be off the Rails.


ruby -v  # 3.3.0
rails -v  # 7.1.3
bundle -v  # 2.4.10
node -v # 20.9.0
git --version # 2.34.1

Before turbo frames

As (every Monday actually;), build the bare minimum files to play with Rails, by creating a route, an associated controller, and a view :

rails new myapp
cd myapp


# Create a default controller
echo "class WelcomeController < ApplicationController" > app/controllers/welcome_controller.rb
echo "end" >> app/controllers/welcome_controller.rb

# Create a default route
echo "Rails.application.routes.draw do" > config/routes.rb
echo '  get "welcome/index"' >> config/routes.rb
echo '  root to: "welcome#index"' >> config/routes.rb
echo 'end' >> config/routes.rb

# Create a default view
mkdir app/views/welcome
echo '<h1>turbo_frame tutorial</h1>' > app/views/welcome/index.html.erb

Then create database,

bin/rails db:create db:migrate

Then launch your local Rails server by typing :

bin/rails server

You should see the title "turbo_frame tutorial" when opening your browser at localhost:3000

Minimalistic turbo_frame

Actually, there is a simpler example, that directly loads the content of a frame from a source.

But I didn't had the use case so far, so I'll show an example where the turbo_frame is shown after a button has been clicked.

More realistic and simple turbo_frame

Controller and route has nothing special, it's plain old Rails.

# inside config/routes.rb

  # add this line, below Rails.application.routes.draw do
  post "full_list", to: "welcome#full_list"
# inside app/controllers/welcome_controller.rb
class WelcomeController < DashboardController

  def full_list


There is nothing special to do in the controller when using turbo_frame

Now the interesting part

<!-- inside app/views/welcome/index.html.erb -->
<!-- add these lines below the h1 title -->

<turbo-frame id="view_more">
  <%= button_to "View all", full_list_path %>

Notice that the turbo-frame element is a HTML custom element.

It's coming from Turbo, so you don't have to define it yourself.

Use <turbo-frame id=""> and not <div id=""> if you want frames to update your DOM.

<!-- inside inside app/views/welcome/full_list.html.erb -->
<turbo-frame id="view_more">
    That's all!

Use .html.erb extension, and not turbo_stream.html.erb

Use the exact same <turbo-frame> id inside the returned partial.

To sum up,

All you have to do is to take care about file and folder naming conventions, and Rails will take care about updating the right element of the DOM.

Checking the code

Relaunch your local web server, and refresh the browser at localhost:3000

When you click the button, you should see "That's all", instead of the button. If this doesn't work, you probably missed something in the above steps :)

Don't forget to check the network request inside the web developer tools of the browser, in order to grab what is going on.


Turbo frame is some kind of weird name, for a very old and simple concept : update the DOM after a user action.

When following convention properly, Rails handles this for you very nicely :)

☝️ Join the junior webdev newsletter

We try to send you every week language-agnostic algorithm exercice and relevant blog articles

Read more