Dialog / Modal
Preview: Form
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'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
Dialog bundles overlay, modal and dialog. Put it inside a DialogTrigger, after the element that opens it; focus moves in on open, is trapped while open, and returns to the trigger on close.
<DialogTrigger>
<Button>New project</Button>
<Dialog>
{({ close }) => (
<>
<DialogHeader title="Create project" description="Projects group issues and docs." />
<DialogBody>…</DialogBody>
<DialogFooter><Button variant="outline" onPress={close}>Cancel</Button><Button onPress={close}>Create</Button></DialogFooter>
</>
)}
</Dialog>
</DialogTrigger>
DialogHeader’s title becomes the dialog’s accessible name; always give one.- Use
AlertDialogfor confirmations that need an answer (not dismissable by clicking outside); adddestructivefor delete-style actions. - For edge panels use
Sheet(no gestures) orDrawer(swipeable, snap points).
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
- Foundation
- Primitive
- react-aria
- React Aria
- Modal + Dialog
- Base UI
- Dialog