Skip to content

Dialog

Modal dialog with focus trapping, dismissal, and ARIA wiring from the Zag.js dialog machine.

Primitive · overlay

Terminal window
npx shadcn@latest add https://ndigo.dev/r/dialog.json

To use the shorter @ndigo/dialog form, configure the namespace in components.json.

Source Target Type
registry/ui/dialog/nd-dialog.ts @ui/nd-dialog/nd-dialog.ts registry:ui
registry/ui/dialog/nd-dialog.css @ui/nd-dialog/nd-dialog.css registry:file

See this component rendered live on the live examples page.

Registry: Ndigo element foundation. Packages: @zag-js/dialog@~1.47.0 (installed automatically).

<nd-dialog> wraps the platform-native modal pattern with Zag’s focus trap, dismissal handling, and ARIA wiring. Markup is yours; behaviour is the machine.

<nd-dialog>
<button data-part="trigger">Invite teammate</button>
<div data-part="content">
<h2 data-part="title">Invite teammate</h2>
<p data-part="description">They will receive an email invitation.</p>
<button data-part="close-trigger">Close</button>
<p>Your own body content goes here.</p>
</div>
</nd-dialog>

A missing trigger is created from trigger-label (or Open dialog). Missing content, positioner, and backdrop wrappers are created on connect, so the short form with body markup alone also works.

Part Element Purpose
trigger button Opens the dialog; carries aria-haspopup/aria-expanded
backdrop div Full-viewport scrim
positioner div Fixed positioning context
content div Dialog surface; carries role="dialog"
title any Labelled by aria-labelledby
description any Described by aria-describedby
close-trigger button Closes the dialog
Attribute Type Description
open boolean Controlled open state; reflected by the element
trigger-label string Label for the generated trigger
initial-focus string Selector for the element focused on open
  • nd-open-change — detail: { open: boolean }, emitted when the dialog opens or closes.
  • show() / hide() — open or close programmatically without a trigger.

Import nd-dialog.css and the design tokens. Every visual value is a --nd-* token; override the tokens rather than the selectors.

Zag owns focus trapping, initial focus, focus restore, Escape, outside-click dismissal, body scroll locking, and the aria-modal/labelledby/describedby contract. Provide a title or an aria-label on the element.