Overview
Dialogs are built on Radix Dialog and Radix Alert Dialog with thin wrappers in components/ui/Dialog.tsx and components/ui/AlertDialog.tsx. We expose a small API for sizing/position, a consistent overlay, tokenized colors, and an optional close button. Use Dialog for general content (forms, pickers), and Alert Dialog for confirmations and destructive actions.
Exports
- Primitives:
Dialog,DialogTrigger,DialogPortal,DialogOverlay,DialogClose - Content & layout:
DialogContent(props:size,position,showCloseButton),DialogHeader,DialogFooter,DialogTitle,DialogDescription - Props:
size:sm·default·lgposition:centered·topshowCloseButton:true | false(defaulttrue)
- Behavior & styling:
- Overlay: blurred, semi-transparent, animated; outside click and
Escclose by default. - Content: rounded, animated in/out, themed with tokens (light/dark).
- Trigger: use
asChildto style a button/link while keeping behavior.
Controlled vs uncontrolled
- Uncontrolled:
<Dialog>withoutopen/onOpenChange(Radix manages state). - Controlled: pass
openandonOpenChangefor complex flows (close on success, block open when invalid, etc.).
Patterns
- Form in a dialog:. Wrap the form inside
DialogContent. For async submit, useReact.useTransition()withTransitionButtonfor pending state. Close on success with your localsetIsOpen(false). Keep footers simple: primary action + secondary cancel (DialogFooter). - Top-positioned sheets: Use
position="top"for short, frequent interactions (e.g., quick create). - Close affordances: Keep the corner close button (
showCloseButton) unless the dialog is a single critical choice (then consider Alert Dialog).
Accessibility
DialogTitle and DialogDescription wire ARIA automatically; focus is trapped while open, and Esc/overlay dismiss by default. Icon-only triggers must have an accessible label (aria-label or visually hidden text).
Alert Dialog
Exports mirror Dialog: AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader/Footer/Title/Description, AlertDialogOverlay/Portal, plus AlertDialogAction and AlertDialogCancel. Use for irreversible actions (delete, reset, leave flow). Actions reuse buttonVariants for consistent styling; drive async work with useTransition + TransitionButton, then close on success.
When to choose which
- General UI (forms, pickers, multi-step content) → Dialog
- Confirm dangerous/critical action → Alert Dialog
- Real link or custom element as trigger →
Trigger asChild - Loading feedback inside actions → TransitionButton with
useTransition()
Customization quick list
- Size & position via
DialogContent size/position. - Corner close visibility via
showCloseButton. - Header/footer composition via
DialogHeader/DialogFooter. - Keep styling via tokens; use
classNameonly for small tweaks - avoid one-off colors.