Dialog
A modal window for a focused task — a short form, a decision or details — that blocks the page until it is closed.
Preview
Installation
pnpm add @syntara/react @syntara/tokensimport { Dialog, DialogTrigger } from '@syntara/react';Usage
import { Button, Dialog, DialogTrigger, TextField } from '@syntara/react';
export function EditProfile() {
return (
<DialogTrigger>
<Button variant="outline">Edit profile</Button>
<Dialog
title="Edit profile"
description="Visible to everyone in your workspace."
footer={({ close }) => <Button onPress={close}>Save</Button>}
>
<TextField label="Full name" />
</Dialog>
</DialogTrigger>
);
}Examples
Sizes
sm, md (default) and lg set the maximum width.
Long content
The body scrolls while the header and footer stay visible.
Accessibility
| Keys | Action |
|---|---|
| EnterorSpace | On the trigger: opens the dialog and moves focus into it. |
| TaborShiftTab | Moves between focusable elements; focus is trapped inside the dialog. |
| Escape | Closes the dialog and returns focus to the trigger. |
- role="dialog" named by the title (h2) and described by the description.
- Everything outside the dialog is hidden from assistive technology and page scrolling is locked while it is open.
- The close button is labelled "Close" and comes last in the tab order, after the footer actions.
- Overlays render in a portal on <body>, outside any ThemeScope. When it opens, the overlay looks up data-syntara-theme, data-syntara-scheme, data-syntara-density, dir and lang — each on the nearest ancestor that has it — starting from its trigger (or from where the component is rendered, when controlled), and copies them onto its own root — so it uses the same tenant tokens and direction as the page region it came from, and nested overlays inherit from their parent overlay.
- Right-to-left: give the ThemeScope a locale (e.g. locale="ar-AE"), which sets dir and wraps React Aria's I18nProvider, so arrow keys and start/end placement flip as well as the layout.
- The backdrop blurs the page lightly and dims it with backdrop-filter: brightness(0.6), so it recedes in light and dark schemes alike. The panel is glass (--syntara-glass-bg + backdrop blur); only text.default and text.subtle sit directly on it, the two roles the theme engine solves to 4.5:1 over any backdrop.
- Motion: the panel fades in and springs up from 0.94 scale with an 8px rise, then the header, body and footer fade up in turn; on narrow screens it rises from the bottom edge instead. With prefers-reduced-motion it appears without moving.
Guidelines
Do
- Keep dialogs to one task with one primary action in the footer.
- Use the render function's close() for Cancel buttons.
- Use a Sheet for long forms or filters that benefit from the full viewport height.
Don’t
- Don't open a dialog from another dialog; replace the content or use a step flow.
- Don't use a Dialog to confirm destructive actions — use AlertDialog.
- Don't put essential information only in the description; it is supporting text.
API reference
Dialog
titleRequiredReactNodeHeading at the top; also the dialog's accessible name.
descriptionReactNodeSupporting text under the title, linked with aria-describedby.
childrenReactNode | (({ close }) => ReactNode)Body content. Laid out as a grid with field-gap spacing; scrolls when taller than the viewport allows.
footerReactNode | (({ close }) => ReactNode)Actions aligned to the inline end. Stacked full-width on narrow screens.
sizesmmddefaultlg
Maximum width of the panel.
isDismissablebooleanWhether clicking the backdrop closes the dialog.
Default
trueisKeyboardDismissDisabledbooleanWhether Escape is ignored.
Default
falseisOpen / defaultOpen / onOpenChangeboolean / boolean / (isOpen: boolean) => voidControlled or uncontrolled open state, for dialogs not placed inside a DialogTrigger.
roledialogdefaultalertdialog
alertdialog also hides the close button and ignores backdrop clicks. Prefer AlertDialog.
className / stylestring / CSSPropertiesApplied to the panel.
DialogTrigger
childrenRequiredReactNodeA pressable trigger (usually a Button) followed by the Dialog, Sheet, AlertDialog or Popover it opens.
isOpen / defaultOpen / onOpenChangeboolean / boolean / (isOpen: boolean) => voidControl the open state from outside.
Tokens
The semantic tokens this component reads, grouped by what they control. Swatches show this site’s theme; change a tenant’s brand and the component follows with no code change.
- Colour4
text.defaultsurface.raisedtext.subtleborder.subtle- Type9
font.bodyfont.size.mdline-height.normalfont.headingfont.size.lgfont.weight.semiboldline-height.snugfont.heading-trackingfont.size.sm- Space and size7
space.16space.4card-insetspace.1control-heightfield-gapspace.2- Shape1
radius.container- Depth4
glass.blurshadow.overlayglass.opacityhairline- Motion7
motion.duration.normalmotion.easing-outmotion.duration.fastmotion.easingmotion.duration.springmotion.springmotion.duration.slow- Other2
sheenrim