Usage
# <% Async modal (loads content via Turbo Frame) %>
<%= ui.btn "Open Modal", url: some_path, data: { turbo_frame: :modal } %>
# <% Sync modal (content already on page) %>
<%= ui.btn "Open Modal", data: { action: "click->modals#show", id: "myModal" } %>
<%= ui.modal(title: "Title", id: "myModal") do %>
<%= ui.modal_body do %>
Content here
<% end %>
<% end %>Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | String | nil | Modal title displayed in the header. |
subtitle | String | nil | Modal subtitle displayed below the title. |
size | String"sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl" | "2xl" | Width of the modal dialog. |
id | String | nil | Unique identifier for sync modals. Required for modals triggered by `modals#show` action. |
Also accepts any HTML attributes via **options (e.g., id:, data:, aria:). class: is also supported for custom styling.
SubcomponentsUse subcomponents below or any HTML.
| Name | Helper | Description |
|---|---|---|
modal_header | ui.modal_header | Header section with title, subtitle, and close button. Automatically rendered when title/subtitle props are provided. |
modal_body | ui.modal_body | Scrollable content area of the modal. |
modal_footer | ui.modal_footer | Footer section typically containing action buttons. |
Examples
Async Modal
<%= ui.btn "Async Modal", url: privacy_path, data: { turbo_frame: :modal } %>Sync Modal
<%= ui.btn "Open Modal", data: { action: "click->modals#show", id: "dialog1" } %>
<%= ui.modal(title: "Modal Title", subtitle: "Modal Subtitle", id: "dialog1") do %>
<p class="p-4">Dialog content</p>
<% end %>Multiple Modals
<div class="flex gap-2">
<%= ui.btn "One modal", data: { action: "click->modals#show", id: "dialog1" } %>
<%= ui.btn "Another modal", variant: :secondary, data: { action: "click->modals#show", id: "dialog2" } %>
</div>
<%= ui.modal(title: "One Modal Title", subtitle: "Modal Subtitle", id: "dialog1") do %>
<p class="p-4">Dialog content</p>
<% end %>
<%= ui.modal(title: "Another Modal Title", subtitle: "Another Subtitle", id: "dialog2") do %>
<p class="p-4">Dialog content 2</p>
<% end %>