ComponentsOverlays

Alert Dialog

A modal question before something hard to undo: delete, disconnect, leave, or discard. Outside clicks do not close it. Focus stays inside until the person answers, then returns to where it was.

No change made.

Usage

Alert dialog usageTSX
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogTitle,
} from "@tulipfarm/sprout/alert-dialog";

<AlertDialog open={confirmStop} onOpenChange={(value) => { if (!busy) setConfirmStop(value); }}>
  <AlertDialogContent>
    <AlertDialogTitle>Stop this plan?</AlertDialogTitle>
    <AlertDialogDescription>
      Unfinished tasks are cancelled and saved agents pause. Finished work is kept.
    </AlertDialogDescription>
    {error && <p role="alert" className="text-sprout-danger">{error}</p>}
    <AlertDialogFooter>
      <AlertDialogCancel disabled={busy}>Keep running</AlertDialogCancel>
      <AlertDialogAction variant="destructive" disabled={busy} aria-busy={busy} onClick={stop}>
        {busy ? "Stopping…" : "Stop plan"}
      </AlertDialogAction>
    </AlertDialogFooter>
  </AlertDialogContent>
</AlertDialog>

AlertDialog works controlled with open and onOpenChange, uncontrolled with AlertDialogTrigger, or mounted only while open with open fixed to true. Ignore the change in onOpenChange to block Escape while work is pending.

AlertDialogCancel closes the dialog. AlertDialogAction is a Button and does not close it, so close it yourself on success and keep it open to show progress or an error.

Sizes

size is "default" (20rem, 24rem from 640px) or "sm" (20rem). With AlertDialogHeader, a default dialog puts AlertDialogMedia beside the text from 640px; sm always centers it and splits the footer into two equal buttons.

Sizes

Both sizes with AlertDialogHeader and AlertDialogMedia. Below 640px both center their header.

default sizeMedia beside the text from 640px
sm sizeCentered, two equal buttons

Confirmations

Most confirmations place the title and description straight in the content without a header. Cancel can run its own onClick, for example to clear a pending choice.

Confirmations

Title and description sit straight in the content. Cancel closes; the action closes the dialog itself before starting the change.

Weekly supplier digestSaved agent
ana@meadow.exampleGoogle integration
Previous webhook keyRotated 2 days ago
Spring launchProject · 12 members
Invoice intakeWorkflow · Runs hourly
Supplier pricing questionsChat · Yesterday
Owning teamPermission edits are not saved

Pending and errors

Disable both buttons and set aria-busy on the action while work runs. Show errors as a role="alert" paragraph or an Alert inside the dialog. When the result is known, hide the action and let Cancel's label say what happens next.

Pending and errors

While work runs, both buttons disable, the action says what is happening, and Escape is ignored. Errors stay inside the dialog.

Supplier onboarding planPlan · 4 of 9 tasks done
Row event queue7 pending · 2 blocked
Row 4f2a9c1ePurchase supplier · 3 linked rows

Progress

A plain Button in the footer can start work that runs inside the dialog, with a role="status" count.

Progress

A plain Button starts the work without closing. The dialog then reports progress, and Cancel's label follows the state.

3 rows selectedPurchase orders · page 1

Review changes

Pick the action variant from what confirming does, and disable it when the review is out of date.

Review changes

The action variant follows what confirming does: default when nothing is lost, destructive when input is cleared. A stale review disables it.

Purchase orders · new rowFields changed while you were editing

Unsaved changes

Guard navigation away from a dirty draft. Pass finalFocus a function when focus should land somewhere other than the trigger.

Unsaved changes

Switching teams or leaving with a dirty draft asks first. finalFocus sends focus to the team that ends up selected.

API

AlertDialog, AlertDialogTrigger, AlertDialogPortal, AlertDialogOverlay, AlertDialogTitle, and AlertDialogDescription wrap the Base UI alert dialog parts and take their props, including render. AlertDialogHeader, AlertDialogFooter, and AlertDialogMedia render a div and accept render.

AlertDialogContent takes size, container, and every Base UI popup prop such as initialFocus and finalFocus. AlertDialogAction takes every Button prop. AlertDialogCancel takes Base UI close props plus variant (default "outline") and size. alertDialogSizeNames lists the sizes.

Accessibility

The popup has role="alertdialog", is named by AlertDialogTitle, and described by AlertDialogDescription. Tab and Shift+Tab stay inside, Escape closes it unless you ignore the change, and outside clicks never close it.

Opening fades and scales in over 180ms; closing takes 120ms. Both turn off when reduced motion is requested.

Theme tokens

Alert dialogs use --sprout-overlay, --sprout-surface, --sprout-canvas, --sprout-secondary, --sprout-line, --sprout-text, --sprout-muted, --sprout-shadow-overlay, and --sprout-radius-panel. They need no brand color, so neutral and TulipFarm themes look alike in light and dark mode.