Alert Dialog
A modal dialog that interrupts the user and expects a response.
Installation
Included in poetry-ui — available as
poetry_alert_dialog
the moment you've installed Poetry,
with no per-component step. To own the source and edit it, copy it into your app:
bin/rails g poetry:add alert-dialog
Submitting a form from the action
A confirmation usually guards a form already on the page: the delete button on a
record, the revoke link on a token. Pass that form's id as
submit: and the action renders as its submit
button (type="submit" plus the
form attribute), so nothing nests inside the
dialog and the activation stays the user's. The destructive-panel block
(bin/rails g poetry:block destructive_panel) shows the
shape.
<%= button_to "Revoke", token_path(token), method: :delete, form: { id: "revoke-token" },
class: "hidden" %>
<%= poetry_alert_dialog do |dialog| %>
<% dialog.with_trigger(variant: :destructive) { "Revoke token" } %>
<% dialog.with_title { "Revoke this token?" } %>
<% dialog.with_description { "Services signed with it fail on their next deploy." } %>
<% dialog.with_cancel { "Keep token" } %>
<% dialog.with_action(variant: :destructive, submit: "revoke-token") { "Revoke token" } %>
<% end %>
Typed confirmation
When the action is grave enough that a click is not enough, ask for the phrase. That
is a Dialog,
not an AlertDialog: the alert dialog carries no fields by contract, and a form belongs in
a dialog that can hold one. The recipe is a form whose input demands the exact phrase
(pattern: plus
required:, so the browser refuses the submit until it
matches, with no JavaScript) and a destructive footer button that submits it through the
form attribute.
Default
<%= poetry_alert_dialog do |dialog| %>
<% dialog.with_trigger(variant: :destructive) { "Delete account" } %>
<% dialog.with_title { "Are you absolutely sure?" } %>
<% dialog.with_description { "This permanently deletes your account and all of its data." } %>
<% dialog.with_cancel { "Cancel" } %>
<% dialog.with_action(variant: :destructive) { "Delete account" } %>
<% end %>
Small
<%= poetry_alert_dialog(size: :sm) do |dialog| %>
<% dialog.with_trigger(variant: :outline) { "Publish changes" } %>
<% dialog.with_title { "Publish these changes?" } %>
<% dialog.with_description { "Your edits go live immediately." } %>
<% dialog.with_cancel { "Cancel" } %>
<% dialog.with_action { "Publish" } %>
<% end %>
Small with media
<%= poetry_alert_dialog(size: :sm) do |dialog| %>
<% dialog.with_trigger(variant: :outline) { "Archive project" } %>
<% dialog.with_media { poetry_icon(name: :"circle-alert") } %>
<% dialog.with_title { "Archive this project?" } %>
<% dialog.with_description { "It moves out of your active workspace. You can restore it from the archive whenever you need it again." } %>
<% dialog.with_cancel { "Cancel" } %>
<% dialog.with_action { "Archive" } %>
<% end %>
With media
<%= poetry_alert_dialog do |dialog| %>
<% dialog.with_trigger(variant: :outline) { "Revoke API key" } %>
<% dialog.with_media { poetry_icon(name: :"triangle-alert") } %>
<% dialog.with_title { "Revoke this API key?" } %>
<% dialog.with_description { "Any service still authenticating with this key will stop working immediately. You can issue a replacement at any time." } %>
<% dialog.with_cancel { "Keep key" } %>
<% dialog.with_action(variant: :destructive) { "Revoke key" } %>
<% end %>
API
Poetry::Ui::AlertDialog::Component — options are
constructor keywords (the poetry_* helper forwards them);
slots are composed inside the block. Generated from the gem's source documentation.
| Option | Type | Details | Description |
|---|---|---|---|
| size: | Symbol | one of: default, sm; defaults to :default |
The panel size; :sm compacts the layout and switches the footer to a two-column grid. |
| content_class: | String | Extra classes merged onto the panel element. |
Slots
| Writer | Description |
|---|---|
| with_action | The confirming choice (required) - a Button; pass variant: :destructive for deletes. Activating it also closes the dialog (a caller-supplied data-action opts out). submit: names the form it submits (type=submit plus the form attribute). |
| with_cancel | The safe way out (required) - an outline Button that takes initial focus and closes the dialog on activation. |
| with_description | The explanation read alongside the title by assistive tech (required). |
| with_media | Optional icon/illustration well above the title. |
| with_title | The heading - the dialog's accessible name (required). |
| with_trigger | The button that opens the dialog; keywords are forwarded as Button props. |
Styling
Every part carries a stable data-slot attribute — target
[data-slot=…] from your own CSS to restyle it. State rides
data attributes on the parts below. This contract is verified against rendered DOM in CI.
| Part | Description |
|---|---|
| [data-slot=alert-dialog] | Root wrapper around the trigger and the <dialog> element |
| [data-slot=alert-dialog-content] | The role=alertdialog <dialog> panel - sizing, animation, and the open state ride here |
| [data-slot=alert-dialog-header] | Title block - holds the optional media well, the title, and the description |
| [data-slot=alert-dialog-media] | The optional media well above the title (an icon or illustration) - the header's first row; absent unless with_media is used |
| [data-slot=alert-dialog-title] | The heading - the alertdialog's accessible name (required slot) |
| [data-slot=alert-dialog-description] | The explanation, wired to aria-describedby (required slot) |
| [data-slot=alert-dialog-footer] | The choice row - cancel then action |
State attributes
| Part | Attribute | Condition | Values |
|---|---|---|---|
| alert-dialog-content | data-open | panel is open (the shared dialog controller flips the pair at runtime) | — |
| alert-dialog-content | data-closed | panel is closed (the server-rendered state) | — |
| alert-dialog-content | data-size | always - the resolved size | default · sm |
Wiring
The Stimulus surface each element carries — declared in the component, verified against rendered DOM in CI. Bare actions fire on the element's default event.
| Element | Controller | Wiring |
|---|---|---|
| root | poetry--core--dialog |
|
| content | poetry--core--dialog |
|
| trigger | poetry--core--dialog |
|
| close | poetry--core--dialog |
|