Components · Overlays
Alert dialog
BetaConfirms a destructive action, such as removing a client.
- Source
components/ui/alert-dialog.tsx - shadcn/ui Alert dialog
- Figma: not linked yet (Q13)
When to use
- To confirm an action that can't be undone: remove a client, delete a program that clients are on, cancel a subscription.
- To confirm leaving with unsaved work: "Discard changes?"
- When the consequence is serious enough that the coach must stop and choose.
When not to use
- For actions that can be undone: do them right away and offer Undo in a Toast. Confirming every delete teaches coaches to click through.
- For a task with fields, such as editing a meal: use a Dialog.
- To show information with only an OK button: use an Alert on the page.
Anatomy
Open the alert dialog above to see its parts: the scrim over the page; the panel with an optional media icon, a title that asks the question, a description of the consequence, and a footer with Cancel and the action (action last). There is no close button: the coach has to choose.
Variants
| Variant | Use for |
|---|---|
Destructive action (variant="destructive" on AlertDialogAction) | Removing or deleting data, cancelling a subscription |
| Default action | Confirmations that aren't destructive, such as publishing a program to 30 clients |
With media (AlertDialogMedia) | An icon that makes the subject clear at a glance, such as a card for billing |
States
| State | What changes | Token |
|---|---|---|
| Opening, closing | Fade and slight zoom; instant with reduced motion | duration-(--duration-base) |
| Open | Scrim over the page, panel on the modal layer | bg-foreground, opacity-(--opacity-overlay), z-(--z-modal) |
| Focus | Starts on Cancel; returns to the trigger on close | ring-ring/50 |
| Click outside | Nothing happens. Only Cancel, the action or Escape close it | none |
The scrim color is a default: there is no overlay color token (QUESTIONS Q6).
Sizes
| Size | Width | Use for |
|---|---|---|
default | Up to max-w-lg; text aligns to the start from the sm breakpoint | Most confirmations, with a description of a sentence or two |
sm | max-w-xs; centered text, buttons side by side | Short questions with a one-line description, such as "Discard changes?" |
Usage guidelines
- The action button repeats the verb in the title: "Remove Sara Al-Otaibi?" → Remove client.
- Use the destructive style for the action only. Cancel stays outline.
- Say what will be lost and whether it can be undone. If billing changes, say when.
- When "Cancel" would be ambiguous, as in cancelling a subscription, name both choices: "Keep subscription" and "Cancel subscription".
Content guidelines
- Title: a question with the verb and the object, sentence case: "Remove Sara Al-Otaibi?", "Discard changes?"
- Description: the consequence in one or two sentences. "This can't be undone." only when it's true.
- Buttons: Cancel (or "Keep …") and a specific verb. Never "OK", "Yes" or "Confirm".
- Arabic: the title as a verbal noun with a question mark: "إزالة سارة العتيبي؟". Buttons use the same verbal noun: "إزالة العميل".
Accessibility
| Key | Does |
|---|---|
| Enter or Space on the trigger | Opens the alert dialog; focus goes to Cancel |
| Tab / Shift+Tab | Moves between Cancel and the action only; focus is trapped |
| Enter or Space | Activates the focused button |
| Escape | Closes it, the same as Cancel, and returns focus to the trigger |
- Rendered as
role="alertdialog"witharia-modal, labelled by the title and described by the description. A screen reader announces "Remove Sara Al-Otaibi?, alert dialog, Her program, check-ins and progress photos will be deleted. This can't be undone." and then "Cancel, button". - Focus starts on Cancel, the safe choice, so pressing Enter by habit doesn't delete anything.
- Clicking the scrim doesn't close it, so a stray click can't be read as a choice.
- Always include an
AlertDialogTitleand anAlertDialogDescription.
RTL
The footer aligns to the end, so Cancel and the action sit on the left in RTL, with the action last (leftmost). In the default size, the title and description align to the start (right). In sm, they are centered and the two buttons share the row, Cancel at the start. The panel is centered in both directions.
Tokens used
Read from components/ui/alert-dialog.tsx at build time, so this list changes when the component does. Opacity modifiers such as /90 are shadcn hover and focus tints on top of the token.
| Token | Utilities | SuperCoach | Coach |
|---|---|---|---|
| --background | bg-background | white | white |
| --foreground | bg-foreground | neutral-950 | neutral-950 |
| --muted | bg-muted | neutral-100 | neutral-100 |
| --muted-foreground | text-muted-foreground | neutral-600 | neutral-600 |
- Layer
z-(--z-modal) - Layer
z-(--z-overlay) - Motion
duration-(--duration-base) - Opacity
opacity-(--opacity-overlay) - Radius
rounded-lg - Radius
rounded-md - Shadow
shadow-lg - Type
text-lg - Type
font-semibold - Type
text-sm
Props
<AlertDialog>
Also takes every prop of Radix AlertDialog.Root
No props of its own.
<AlertDialogTrigger>
Also takes every prop of Radix AlertDialog.Trigger
No props of its own.
<AlertDialogContent>
Also takes every prop of Radix AlertDialog.Content
| Prop | Type | Default |
|---|---|---|
| size? | "default" | "sm" | "default" |
<AlertDialogHeader>
Also takes every prop of <div>
No props of its own.
<AlertDialogFooter>
Also takes every prop of <div>
No props of its own.
<AlertDialogTitle>
Also takes every prop of Radix AlertDialog.Title
No props of its own.
<AlertDialogDescription>
Also takes every prop of Radix AlertDialog.Description
No props of its own.
<AlertDialogMedia>
Also takes every prop of <div>
No props of its own.
<AlertDialogAction>
Also takes every prop of Radix AlertDialog.Action
| Prop | Type | Default |
|---|---|---|
| variant? | from <Button> | "default" |
| size? | from <Button> | "default" |
<AlertDialogCancel>
Also takes every prop of Radix AlertDialog.Cancel
| Prop | Type | Default |
|---|---|---|
| variant? | from <Button> | "outline" |
| size? | from <Button> | "default" |
AlertDialogCancel and AlertDialogAction also take Button's variant and size. Cancel defaults to outline, the action to default.
Replaces in coach-admin
From the read-only audit of coach-admin: 90 style values, 111 uses.
coach-admin's confirmation modals (feature changes, deleting progress images, bulk status changes, exports, and the Bootstrap .confirmation-modal) become this component.
Classes and selectors
.feature-confirm-modal__row5.feature-confirm-modal__feature-icon4.feature-confirm-modal__meta-sep3.feature-confirm-modal__feature-name3.error-boundary-report-confirmation3.feature-confirm-modal__foot3.confirmation-modal .modal-footer .btn-danger, .confirmation2.feature-confirm-modal__badge2.confirm-cancel-button2.feature-confirm-modal__subtitle2.feature-confirm-modal__feature-meta2.feature-confirm-modal__head2
Files
src/reusableComponents/features/FeatureChangeConfirmModal.scss69src/reusableComponents/DeleteImagesModal/DeleteImagesModal.scss26src/views/User/components/ExportConfirmationModal.scss3src/views/User/components/clients-list/BulkStatusConfirmBody.scss2src/reusableComponents/DeleteImagesModal/DeleteImagesModal.tsx1
The inventory lists the first 12 locations of each value, so file counts are a lower bound.
SCSS variables in these styles
$subtitle-text-color→--muted-foreground$border-strong-color→--border-strong$light-primary-colornot a color: spacing, size or layout$light-surface-bg→--muted$danger-text-color→--destructive-text$danger-bg-color→--destructive-subtle$spacing-2xsnot a color: spacing, size or layout$border-color→--border$success-color→ nearest green-500 (no semantic token)$spacing-mdnot a color: spacing, size or layout$spacing-xsnot a color: spacing, size or layout$spacing-smnot a color: spacing, size or layout