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)
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 moreclass 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.
Let’s work together to build or elevate your Ruby on Rails application to the next level!