Dialog

A modal dialog that interrupts the user with important content and expects a response.

Requires JavaScript

Installation

Add the component to your project:

rails generate shadcn:component dialog

Usage

<%= render Shadcn::DialogComponent.new do |dialog| %>
  <% dialog.with_trigger do %>
    <%= render Shadcn::ButtonComponent.new(variant: :outline) do %>Open Dialog<% end %>
  <% end %>
  <% dialog.with_body do |content| %>
    <% content.with_header do |header| %>
      <% header.with_title { "Dialog Title" } %>
      <% header.with_description { "Dialog description here." } %>
    <% end %>
    <p>Dialog body content goes here.</p>
    <% content.with_footer do %>
      <%= render Shadcn::ButtonComponent.new { "Save" } %>
    <% end %>
  <% end %>
<% end %>

Examples

Basic Dialog

<%= render Shadcn::DialogComponent.new do |dialog| %>
  <% dialog.with_trigger do %>
    <%= render Shadcn::ButtonComponent.new(variant: :outline) do %>Open<% end %>
  <% end %>
  <% dialog.with_body do |content| %>
    <% content.with_header do |header| %>
      <% header.with_title { "Are you sure?" } %>
      <% header.with_description { "This action cannot be undone." } %>
    <% end %>
    <% content.with_footer do %>
      <div class="flex gap-2 justify-end">
        <%= render Shadcn::ButtonComponent.new(variant: :outline, data: { action: "click->shadcn--dialog#close" }) { "Cancel" } %>
        <%= render Shadcn::ButtonComponent.new(variant: :destructive) { "Delete" } %>
      </div>
    <% end %>
  <% end %>
<% end %>

Custom Close Button

Use data-action="click->shadcn--dialog#close" on any element to close the dialog.

<%= render Shadcn::ButtonComponent.new(
  variant: :ghost,
  size: :icon,
  data: { action: "click->shadcn--dialog#close" }
) do %>
  <svg>X</svg>
<% end %>

With Form

API Reference

DialogComponent

API Reference

Prop Type Default Description
id String nil Unique identifier for the dialog (useful for Turbo Stream targeting)
open Boolean false Whether the dialog starts in open state
modal Boolean true Whether dialog is modal (traps focus, blocks background interaction)

Slots

Slot Description
with_trigger The element that opens the dialog (usually a button)
with_body The dialog content container (yields DialogContentComponent)

DialogContentComponent Slots

Slot Description
with_header Header section (yields with_title and with_description slots)
with_title Dialog title text
with_description Dialog description text
with_footer Footer section (usually contains action buttons)
with_close_button Custom close button element

Stimulus Controller

This component requires JavaScript. The Stimulus controller shadcn--dialog provides interactivity.

Manages dialog open/close state, focus trapping, keyboard navigation, and accessibility.

Installation

Add to your config/importmap.rb:

pin "shadcn-rails", to: "shadcn/index.js"

Then in your app/javascript/controllers/index.js:

import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn-rails"

const application = Application.start()
registerShadcnControllers(application)

Or import just this controller:

import DialogController from "shadcn-rails/controllers/dialog_controller"

application.register("shadcn--dialog", DialogController)

Targets

Name Description
trigger The element that triggers the dialog to open
template Template containing the dialog content (for portal rendering)
overlay The backdrop overlay element
content The dialog content container

Values

Name Type Default Description
open Boolean false Current open/closed state
modal Boolean true Whether dialog is modal

Actions

Action Description
open Opens the dialog
close Closes the dialog

TypeScript

Type definitions are included. Import types as needed:

import type { DialogController } from "shadcn-rails"

Accessibility

  • Uses role="dialog" for proper screen reader announcement
  • Sets aria-modal="true" when modal is enabled
  • Traps focus within the dialog when open
  • Pressing Escape closes the dialog
  • Returns focus to trigger element when closed
  • Links title and description via aria-labelledby and aria-describedby