Mateus Nava

Mateus Nava

February 03, 2022

Modal with image carousel using Turbo-Frames

by Klaudia Piaskowska (unsplash.com)
by Klaudia Piaskowska (unsplash.com)
Today's challenge is to create a modal with an image carousel using just the Hotwire turbo (no JS). Something similar:

Example

The idea is to have a list of galleries, when the user clicks on the gallery, the modal will open and the user will be able to navigate the list of photos.

The first step is to have a page with a list of galleries:
<%= turbo_frame_tag :modal %> # Where the content will be render

<h1>My Galleries</h1>
<ul>
  <li><%= link_to 'Sports', modal_gallery_path('sports'), data: {'turbo_frame' => 'modal'} %></li> # data-turbo-frame to indicates thats navigation will replace modal frame
  <li><%= link_to 'Nature', modal_gallery_path('nature'), data: {'turbo_frame' => 'modal'} %></li>
</ul>
Galleries



On the link, you can specify which part of the page needs to be replaced (attr data-turbo_frame), this is possible because of the turbo-frame. For our purpose we created a route that returns the HTML of the modal, this route is the modal_gallery_path route.

  1. User clicks on the gallery (link modal_gallery_path)
  2. Controllers return the HTML of the modal
  3. Turbo replaces the "modal" frame with the response

The controller doesn't need any special code, it just renders the modal HTML.

Modal HTML
<%= turbo_frame_tag :modal do %>
  <div class="layer"></div>
  <div class="simple-modal">
    <div class="content">
      <img src="https://picsum.photos/400/300?q=<%= Time.current.to_i %>" />
      <br />
      <%= link_to 'Próxima', modal_gallery_path('random') %>
    </div>
  </div>
<% end %>

Modal CSS 
.layer {
  background: rgba(0,0,0,0.8);
  position: fixed;
  height: 100%;
  width: 100%;
  top: 0;
  left: 0;
}

.simple-modal {
  position: fixed;
  top: 0;
  left: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  width: 100%;
}

.simple-modal .content {
  background: white;
  padding: 10px;
}

That's all, pretty nice :)


Final result