Root API
Dialog is the root state container for modal behavior.
| Prop | Type | Default |
|---|---|---|
open | boolean | — |
| Whether the modal is currently open. When provided, the modal becomes a controlled component. | ||
defaultOpen | boolean | false |
| Whether the modal is default open. | ||
onChangeOpen | (state: boolean) => void | — |
| Callback fired when the modal's open state changes. Receives the next boolean state. | ||
children | ReactNode | ReactNode[] | — |
| The content rendered inside the dialog. Can include headings, text, actions, and nested components. | ||
fluid | boolean | — |
| Makes the dialog fluid, allowing it to stretch responsively within its container. Useful for adapting to different screen sizes or layouts. | ||
Child Parts API
DialogTrigger
Open action for the dialog.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | — |
If true, renders the trigger as a child element using Slot. Allows for custom wrapper elements (e.g., <a>, <div>) to behave as modal triggers. | ||
ref | Ref<HTMLButtonElement> | — |
Ref forwarded to the underlying trigger element (typically a <button>). Useful for focus control or imperative access. | ||
Also accepts all <button> attributes.
- Typical usage:
asChildwithButton - Should remain inside
Dialog - Sets
aria-haspopup='dialog'andaria-expanded
DialogContent
The native modal <dialog>.
| Prop | Type | Default |
|---|---|---|
shadowed | boolean | true |
| Applies a visual shadow to the dialog panel. Adds depth and separation from the background. | ||
blurred | boolean | true |
| Blurs the page behind the dialog. | ||
overlay | boolean | true |
| Dims the page behind the dialog. When false, the page stays visible and the dialog stays modal. | ||
closedBy | ModalDialogClosedBy | 'closerequest' |
Which user actions close the dialog, like the native closedby attribute: any a backdrop click or Escape, closerequest only Escape, none neither. | ||
ref | Ref<HTMLDialogElement> | — |
Ref forwarded to the native <dialog> element. Useful for managing focus, animations, or measurements. | ||
children | ReactNode | — |
| The children nodes to render inside the dialog. | ||
Also accepts all <dialog> attributes.
- It sets no
idoraria-labelledbyitself: name it witharia-labelledbypointing to your heading'sid, or witharia-label.onCancelandonCloserun after the internal handlers. blurred(defaulttrue) blurs the page behind the dialog;overlay(defaulttrue) dims it, and withoverlay={false}the dialog stays modal over a transparent backdrop;shadowed(defaulttrue) adds the surface shadow.closedBysets which user actions close the dialog, like the nativeclosedbyattribute:'any'(a backdrop click orEscape),'closerequest'(Escapeonly, the default), or'none'. A backdrop click does not close the dialog unlessclosedBy='any'.- Closes on submit of a
<form method="dialog">inside it, also withclosedBy='none'. The close goes throughonChangeOpen(false), so the close transition plays and a controlled parent can keep it open; the submit button'svaluebecomes the dialog'sreturnValue. - Stays mounted only while open and while the close transition plays.
DialogClose
Closes the dialog when clicked. It has no styles, icon, or default aria-label: render your own button inside it with asChild and label it.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | — |
If true, renders the close action as its child element using Slot, so any button of your own closes the dialog. | ||
ref | Ref<HTMLButtonElement> | — |
| Ref forwarded to the underlying button. | ||
Also accepts all <button> attributes.
- The close goes through
onChangeOpen(false), so the close transition plays and a controlled parent can keep the dialog open. - Use it for a standalone close button, such as the X in a header. For buttons that answer the dialog (Cancel, Confirm, a
returnValue), use a<form method="dialog">. WithoutasChildit renderstype="button", so it also works inside a form of your own without submitting it; withasChildgive your own buttontype="button". - Your
onClickruns after the close request, so it can record which button closed the dialog.
close-with-handler.tsx · 55 lines
import { useId, useState, type CSSProperties } from 'react';
import {
Button,
Dialog,
DialogClose,
DialogContent,
DialogTrigger,
Heading,
Icon,
IconButton,
Text,
} from '@vega-ui/react';Hooks
useDialogContext
Advanced hook for custom wrappers and close actions. Returns { open, changeOpen, fluid }.
Use it only when the exported parts are not enough for the desired composition.
Types
| Type | Definition | Notes |
|---|---|---|
DialogProps | Root prop type | Open-state API lives here. |
DialogTriggerProps | Trigger part prop type | Trigger composition contract. |
DialogContentProps | Content part prop type | Content container props. |
DialogCloseProps | Close part prop type | <button> attributes plus asChild. |
State Model
- Open state can be controlled with
openor uncontrolled withdefaultOpen. DialogTriggeris the normal open path for uncontrolled usage.- Every close request allowed by
closedBy(backdrop click,Escape) everyDialogCloseclick, and every<form method="dialog">submit go throughonChangeOpen(false); a controlled dialog stays open untilopenbecomesfalse. - When the browser closes the dialog on its own while
openis stilltrue, the dialog reopens.
Integration Notes
- Name every dialog with
aria-labelledbyoraria-labelonDialogContent. - To close from inside, use
DialogClosefor a standalone close button, buttons in a<form method="dialog">for actions that answer the dialog, or a controlledopenand a button that callssetOpen(false). - Retest nested overlays in real composition, not only in isolation.
- Keep long content scrollable so dismissal and actions stay usable.