Skip to content
v2.5.0
English
Русский
Documentation

Dialog

Dialog is a compound component for modal overlays with root, trigger, and content parts.

Root API

Dialog is the root state container for modal behavior.

PropTypeDefault
openboolean—
Whether the modal is currently open. When provided, the modal becomes a controlled component.
defaultOpenbooleanfalse
Whether the modal is default open.
onChangeOpen(state: boolean) => void—
Callback fired when the modal's open state changes. Receives the next boolean state.
childrenReactNode | ReactNode[]—
The content rendered inside the dialog. Can include headings, text, actions, and nested components.
fluidboolean—
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.

PropTypeDefault
asChildboolean—
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.
refRef<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: asChild with Button
  • Should remain inside Dialog
  • Sets aria-haspopup='dialog' and aria-expanded

DialogContent

The native modal <dialog>.

PropTypeDefault
shadowedbooleantrue
Applies a visual shadow to the dialog panel. Adds depth and separation from the background.
blurredbooleantrue
Blurs the page behind the dialog.
overlaybooleantrue
Dims the page behind the dialog. When false, the page stays visible and the dialog stays modal.
closedByModalDialogClosedBy'closerequest'
Which user actions close the dialog, like the native closedby attribute: any a backdrop click or Escape, closerequest only Escape, none neither.
refRef<HTMLDialogElement>—
Ref forwarded to the native <dialog> element. Useful for managing focus, animations, or measurements.
childrenReactNode—
The children nodes to render inside the dialog.

Also accepts all <dialog> attributes.

  • It sets no id or aria-labelledby itself: name it with aria-labelledby pointing to your heading's id, or with aria-label. onCancel and onClose run after the internal handlers.
  • blurred (default true) blurs the page behind the dialog; overlay (default true) dims it, and with overlay={false} the dialog stays modal over a transparent backdrop; shadowed (default true) adds the surface shadow.
  • closedBy sets which user actions close the dialog, like the native closedby attribute: 'any' (a backdrop click or Escape), 'closerequest' (Escape only, the default), or 'none'. A backdrop click does not close the dialog unless closedBy='any'.
  • Closes on submit of a <form method="dialog"> inside it, also with closedBy='none'. The close goes through onChangeOpen(false), so the close transition plays and a controlled parent can keep it open; the submit button's value becomes the dialog's returnValue.
  • 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.

PropTypeDefault
asChildboolean—
If true, renders the close action as its child element using Slot, so any button of your own closes the dialog.
refRef<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">. Without asChild it renders type="button", so it also works inside a form of your own without submitting it; with asChild give your own button type="button".
  • Your onClick runs 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

TypeDefinitionNotes
DialogPropsRoot prop typeOpen-state API lives here.
DialogTriggerPropsTrigger part prop typeTrigger composition contract.
DialogContentPropsContent part prop typeContent container props.
DialogClosePropsClose part prop type<button> attributes plus asChild.

State Model

  • Open state can be controlled with open or uncontrolled with defaultOpen.
  • DialogTrigger is the normal open path for uncontrolled usage.
  • Every close request allowed by closedBy (backdrop click, Escape) every DialogClose click, and every <form method="dialog"> submit go through onChangeOpen(false); a controlled dialog stays open until open becomes false.
  • When the browser closes the dialog on its own while open is still true, the dialog reopens.

Integration Notes

  • Name every dialog with aria-labelledby or aria-label on DialogContent.
  • To close from inside, use DialogClose for a standalone close button, buttons in a <form method="dialog"> for actions that answer the dialog, or a controlled open and a button that calls setOpen(false).
  • Retest nested overlays in real composition, not only in isolation.
  • Keep long content scrollable so dismissal and actions stay usable.