Alert Dialog
Preview: Alert
Modal dialog: overlay + modal + dialog in one. Put it inside a DialogTrigger, after the trigger button.
Import
import { Dialog, DialogHeader, DialogBody, DialogFooter, AlertDialog, DialogTrigger } from '@marbleui/ui'This is a style of dialog; see its examples for all variants.
Props
<Dialog>
| Prop | Type | Default | Description |
|---|---|---|---|
| children *required | ReactNode | — | |
| isDismissable | boolean | true | |
| overlayProps | Omit<ModalOverlayProps, 'children'> | — | |
| size | 'sm' | 'md' | 'lg' | 'md' |
Also accepts React Aria props (81).
<DialogHeader>
| Prop | Type | Default | Description |
|---|---|---|---|
| title *required | ReactNode | — | |
| className | string | — | |
| description | ReactNode | — |
<DialogBody>
| Prop | Type | Default | Description |
|---|---|---|---|
| children *required | ReactNode | — | |
| className | string | — | |
| id | string | — |
<AlertDialog>
Confirmation dialog for destructive or important actions (role="alertdialog"). The body describes the dialog (aria-describedby). Focus starts on the action, or on Cancel when `destructive`, so Enter can't confirm by accident.
| Prop | Type | Default | Description |
|---|---|---|---|
| actionLabel *required | string | — | |
| children *required | ReactNode | — | |
| title *required | ReactNode | — | |
| cancelLabel | string | 'Cancel' | |
| destructive | boolean | — | |
| onAction | () => void | — |
<DialogTrigger>
Re-exported from React Aria DialogTrigger; see its documentation for props.
Accessibility
Keyboard interaction, focus management and ARIA semantics come from the underlying primitives: React Aria Dialog · React Aria DialogTrigger · React Aria Heading · React Aria Modal · React Aria ModalOverlay. Follow the primitive's docs for the full keyboard map.
Usage notes
AlertDialog is the confirmation style of Dialog: a small modal with role="alertdialog", a title, a message, and Cancel plus one action. Put it in a DialogTrigger after the button that opens it.
<DialogTrigger>
<Button variant="danger">Delete workspace</Button>
<AlertDialog title="Delete workspace?" actionLabel="Delete" destructive onAction={deleteWorkspace}>
This permanently removes 12 projects and 340 issues.
</AlertDialog>
</DialogTrigger>
- Clicking outside doesn’t close it; Escape and the cancel button (
cancelLabel) do, without callingonAction. onActionruns and the dialog closes straight away. There’s no pending or error state, so for a request that can fail build it fromDialogand your ownDialogFooter.- Focus starts on the action button, so Enter confirms at once, except with
destructive, where it starts on Cancel. Label the action with the verb (“Delete”, not “OK”) and put the consequence in the message, which is the dialog’s description (aria-describedby). - For lighter, undoable confirmations next to the trigger use
Popconfirm.
Example source · show· hide
import { Button } from '../button'
import { Select, SelectItem } from '../select'
import { TextField } from '../text-field'
import { AlertDialog, Dialog, DialogBody, DialogFooter, DialogHeader, DialogTrigger } from './dialog'
export const styles = {
Form: () => (
<DialogTrigger>
<Button>New project</Button>
<Dialog>
{({ close }) => (
<>
<DialogHeader title="Create project" description="Projects group issues, docs and members." />
<DialogBody className="flex flex-col gap-4">
<TextField label="Name" placeholder="Website redesign" autoFocus />
<Select label="Team" defaultSelectedKey="design">
<SelectItem id="design">Design</SelectItem>
<SelectItem id="eng">Engineering</SelectItem>
<SelectItem id="growth">Growth</SelectItem>
</Select>
</DialogBody>
<DialogFooter>
<Button variant="outline" onPress={close}>Cancel</Button>
<Button onPress={close}>Create</Button>
</DialogFooter>
</>
)}
</Dialog>
</DialogTrigger>
),
Alert: () => (
<DialogTrigger>
<Button variant="danger">Delete workspace</Button>
<AlertDialog title="Delete workspace?" actionLabel="Delete" destructive>
This permanently removes 12 projects and 340 issues. This can't be undone.
</AlertDialog>
</DialogTrigger>
),
Content: () => (
<DialogTrigger>
<Button variant="outline">Terms of service</Button>
<Dialog size="lg">
{({ close }) => (
<>
<DialogHeader title="Terms of service" description="Last updated October 2026" />
<DialogBody className="max-h-72 space-y-3 leading-relaxed">
{Array.from({ length: 6 }, (_, i) => (
<p key={i}>
{i + 1}. You keep ownership of everything you create. We only process it to run the service, and you can
export or delete it at any time.
</p>
))}
</DialogBody>
<DialogFooter>
<Button onPress={close}>I agree</Button>
</DialogFooter>
</>
)}
</Dialog>
</DialogTrigger>
),
}Source: packages/ui/src/dialog/dialog.tsx
Catalog
- Category
- overlays
- Priority
- Core
- Primitive
- react-aria
- React Aria
- Dialog (role="alertdialog")
- Base UI
- Alert Dialog