Skip to main content

Dialog

Stable

Modal overlay with focus trap, Escape-to-close, and automatic focus restoration to the trigger element. Dialog.Title is required for screen reader accessibility.

OverlayCompoundFocus trapVhyxSeal

Interactive example

Edit profile dialog

Import

tsx
import { Dialog } from '@vhyxui/react'

// Sub-components
// Dialog.Trigger     — the element that opens the dialog
// Dialog.Portal      — renders content outside DOM hierarchy
// Dialog.Overlay     — the backdrop
// Dialog.Content     — the dialog panel
// Dialog.Header      — header slot
// Dialog.Footer      — footer slot for actions
// Dialog.Title       — required accessible title
// Dialog.Description — optional description
// Dialog.Close       — button to close

Variants

Confirmation dialog (destructive)

Props

PropTypeDefaultDescription
openbooleanControlled open state.
defaultOpenbooleanfalseDefault open state for uncontrolled usage.
onOpenChange(open: boolean) => voidCalled when the open state changes.
modalbooleantrueWhen true, traps focus and renders the overlay.
contractPartial<ComponentContract>VhyxSeal contract override.

Sub-components: Dialog.Trigger accepts asChild. Dialog.Content accepts standard HTMLDivElement attributes.

Accessibility

  • role="dialog", aria-modal="true", aria-labelledby pointing to Dialog.Title.
  • Dialog.Title is required — a development warning is logged if absent.
  • Focus is trapped inside the dialog while open. Tab cycles only within.
  • On close, focus returns to the exact trigger element that opened the dialog.
  • Escape always closes the dialog and restores focus.
  • Overlay click closes the dialog by default.

Keyboard navigation

KeyAction
EscapeClose the dialog and return focus to the trigger.
TabCycle through focusable elements inside the dialog.
Shift + TabReverse focus cycle within the dialog.

Agent contract

Default VhyxSeal contract shipped with every Dialog.

Default contract
{
  "type": "confirmation",
  "intent": "open-dialog",
  "description": "Opens a modal dialog overlay that interrupts the current workflow",
  "requires": [],
  "requiredPermissions": [],
  "consequence": "Renders a blocking overlay — underlying page is inaccessible until dismissed",
  "affects": [
    "view"
  ],
  "reversible": true,
  "safetyLevel": "low",
  "requiresConfirmation": false,
  "destructive": false,
  "contractVersion": "0.0.1",
  "fingerprint": "vhyxs_4ae3824b"
}

Theming

Override these CSS tokens to theme Dialog.

--vhyx-z-modalZ-index (400)
--vhyx-z-overlayOverlay z-index (300)
--vhyx-shadow-2xlContent shadow
--vhyx-radius-xlContent border radius
--vhyx-duration-slowEntry animation duration
--vhyx-easing-springContent slide-up easing

Examples

Controlled dialog

tsx
const [open, setOpen] = useState(false)

<Dialog open={open} onOpenChange={setOpen}>
  <Dialog.Trigger asChild>
    <Button>Edit settings</Button>
  </Dialog.Trigger>
  <Dialog.Portal>
    <Dialog.Overlay />
    <Dialog.Content>
      <Dialog.Title>Settings</Dialog.Title>
      {/* content */}
      <Dialog.Footer>
        <Button onClick={() => setOpen(false)}>Done</Button>
      </Dialog.Footer>
    </Dialog.Content>
  </Dialog.Portal>
</Dialog>

Open dialog programmatically

Open without a Trigger sub-component