Alert Dialog
Stable Stimulus:senren--alert-dialog
destructive action confirmation
Are you absolutely sure?
This action cannot be undone. This will permanently delete the project and remove all of its data.
Usage example #
Copy this ERB into a Rails view after installing the component. The snippet below is the same code used by the live preview above.
<div class="flex w-full justify-center">
<%= render Senren::AlertDialogComponent.new(variant: :destructive) do |d| %>
<% d.with_trigger do %>
<%= render(Senren::ButtonComponent.new(variant: :destructive)) { "Delete project" } %>
<% end %>
<% d.with_title { "Are you absolutely sure?" } %>
<% d.with_description { "This action cannot be undone. This will permanently delete the project and remove all of its data." } %>
<% d.with_cancel do %>
<button type="button" data-action="click->senren--alert-dialog#close" class="cursor-pointer inline-flex h-10 items-center rounded-md border border-[hsl(var(--senren-border))] bg-[hsl(var(--senren-background))] px-4 text-sm font-medium hover:bg-[hsl(var(--senren-accent))]">Cancel</button>
<% end %>
<% d.with_confirm do %>
<%= render(Senren::ButtonComponent.new(variant: :destructive)) { "Delete" } %>
<% end %>
<% end %>
</div>
Install this component #
Copy the official component into your app
This component requires Stimulus. Keep --client so the controller is copied with the ViewComponent.
bin/rails senren:add alert_dialog --client
Create a custom component with the same conventions
Use this when you need an app-specific component that follows Senren's ViewComponent and Stimulus structure. --client is required for this behavior.
bin/rails generate senren:component alert_dialog --client
Dependencies are resolved by senren:add:
button, dialog.
At a glance #
Source #
<div data-controller="senren--alert-dialog" data-senren-component="alert_dialog" id="<%= dom_id %>">
<% if trigger? %>
<span data-action="click->senren--alert-dialog#open" data-senren--alert-dialog-target="trigger">
<%= trigger %>
</span>
<% else %>
<button type="button" data-action="click->senren--alert-dialog#open"
data-senren--alert-dialog-target="trigger"
class="hidden">Open</button>
<% end %>
<div data-senren--alert-dialog-target="overlay" hidden
class="fixed inset-0 z-40 bg-black/50 backdrop-blur-sm"></div>
<div data-senren--alert-dialog-target="panel" hidden
role="alertdialog" aria-modal="true" aria-labelledby="<%= dom_id %>-title" aria-describedby="<%= dom_id %>-desc"
tabindex="-1"
class="fixed left-1/2 top-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-(--senren-radius) border border-[hsl(var(--senren-border))] bg-[hsl(var(--senren-popover))] text-[hsl(var(--senren-popover-foreground))] p-6 shadow-lg">
<% if title? %>
<h2 id="<%= dom_id %>-title" class="text-lg font-semibold"><%= title %></h2>
<% end %>
<% if description? %>
<p id="<%= dom_id %>-desc" class="mt-2 text-sm text-[hsl(var(--senren-muted-foreground))]"><%= description %></p>
<% end %>
<div class="mt-6 flex justify-end gap-2">
<% if cancel? %>
<span data-action="click->senren--alert-dialog#close"><%= cancel %></span>
<% end %>
<% if confirm? %>
<%= confirm %>
<% end %>
</div>
</div>
</div>
# frozen_string_literal: true
module Senren
class AlertDialogComponent < BaseComponent
renders_one :trigger
renders_one :title
renders_one :description
renders_one :cancel
renders_one :confirm
VARIANTS = { default: '', destructive: '' }.freeze
SIZES = { md: '' }.freeze
def initialize(variant: :default, id: nil, class_name: nil, **html)
super(variant: variant, size: :md, class_name: class_name, **html)
@dom_id = id || "senren-alert-dialog-#{SecureRandom.hex(3)}"
end
attr_reader :dom_id
end
end
AI agent rules #
Use for
- +destructive action confirmation
- +irreversible operations
Avoid
- -routine modal forms - use dialog
Accessibility #
- role=alertdialog with aria-labelledby.
- Confirm action receives initial focus only when non-destructive.