Creating a Modal Form in Rails 8.0

Creating a Modal Form in Rails 8.0

Feti Jashari Feti Jashari
Rails Hotwire Modal

Reusable Modals in Rails 8.0

1734115793769.png 119 KB


Learn how to create a single, reusable modal component in Rails 8.0 with View Components. This streamlined approach works seamlessly across all your resources, simplifying development and maintaining consistency. Includes a detailed demo and step-by-step instructions to help you get started.

Let’s dive in!

Wondering what Hotwire is? Hotwire is a modern web development approach that speeds up applications by sending HTML over the wire instead of JSON. With tools like Turbo for fast navigation and real-time updates, and Stimulus for adding custom behavior, Hotwire reduces the need for custom JavaScript. Created by 37signals, it’s a simple way to build fast, responsive web and mobile apps. Read more at https://hotwired.dev/

Prerequisites: This assumes that you have already a Rails 8.0 running 

  •  Add the TailwindCSS Stimulus Components

bin/importmap pin tailwindcss-stimulus-components

next, make sure you register the Modal Component

// app/javascript/controllers/index.js

import { Application } from "@hotwired/stimulus"

const application = Application.start();

import { Modal } from "tailwindcss-stimulus-components"
application.register('modal', Modal)

For more components and detailed steps, follow instructions here: TailwindCSS Stimulus Components


bundle add view_component


./bin/bundle add tailwindcss-rails
./bin/rails tailwindcss:install


Turbo Modal - Component 


Start by generating a new Turbo Modal Component

bin/rails generate component TurboModal title

this will generate 2 files:

create  app/components/turbo_modal_component.rb
invoke  erb
create    app/components/turbo_modal_component.html.erb

Before we start working on Turbo Modal Component, we need to add a frame tag (<%= turbo_frame_tag "modal" %>), within app/views/layouts/application.html.erb

<!-- app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
  <head>
    ....
  </head>

  <body>

    <%= turbo_frame_tag "modal" %> 

    <%= yield %>
  </body>
</html>

next, within app/components/turbo_modal_component.rb, paste the following:

class TurboModalComponent < ViewComponent::Base
  include Turbo::FramesHelper

  def initialize(title:)
    @title = title
  end
end

and within app/components/turbo_modal_component.html.erb, paste the following:

<%= turbo_frame_tag "modal" do %>
  <div data-controller="modal" data-modal-open-value="true">
    <dialog data-modal-target="dialog" class="p-8 min-w-[672px] rounded-lg backdrop:bg-black/80">
      <button type="button" data-action="modal#close:prevent" class="absolute top-5 right-5">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4">
          <line x1="18" x2="6" y1="6" y2="18"></line>
          <line x1="6" x2="18" y1="6" y2="18"></line>
        </svg>
        <span class="sr-only">Close</span>
      </button>
      <h2 class="text-lg"><%= @title %></h2>
      <div class="my-2 min-h-56">
        <%= content %>
      </div>
    </dialog>
  </div>
<% end %>

at this point you should be ready to start using the Turbo Modal we just made.
Here is an example, use case we used on one of our projects. In short all we had to do from this point on, wrap the content you want to render within this turbo component and - that's it.

Use Case - with Blog Post

We used scaffold to generate a Post with title

rails g scaffold Post title

within Post model we added body (has_rich_text) - Read more

class Post < ApplicationRecord
  has_rich_text :body

  validates :title, presence: true
end

then all we had to do wrap the content of new.html.erb and edit.html.erb with our newly made Turbo Modal Component.

<!-- app/views/posts/new.html.erb -->

<%= render TurboModalComponent.new(title: "New Post") do %>
  <%= render "form", post: @post %>
<% end %>

and

<!-- app/views/posts/edit.html.erb -->
<%= render TurboModalComponent.new(title: "Edit Post") do %>
  <%= render "form", post: @post %>
<% end %>

now, we need to modify our new and edit links, and add turbo_frame data attribute:

<!-- app/views/posts/index.html.erb -->
<%= link_to "New post", new_post_path, data: { turbo_frame: "modal" } %>

<!-- app/views/posts/show.html.erb -->
<%= link_to "Edit this post", edit_post_path(@post), data: { turbo_frame: "modal" } %>

Thats it - there you have it :). One modal component for all your resources. Simply, repeat the last 3 steps on other resources and it will work just fine.

DEMO
1734113793281.gif 1.02 MB


Let us know if you want the source code. Will be happy to share.

Looking for Ruby on Rails Expertise?
If you have a new Ruby on Rails project or need assistance with upgrading and optimizing an existing application, we’re here to help. At fetosoft, we specialize in developing robust, scalable, and maintainable Ruby on Rails applications tailored to your business needs.

👉 Request a quotation today: https://fetosoft.com/quotes/new
Let’s work together to build or elevate your Ruby on Rails application to the next level!

Your Next Project Starts Here.

Let’s collaborate to solve challenges and develop your product—request your quote today!