Skip to content
Primitives

Dialog

Modal dialog framed with corner-bracket reticles and a hard offset shadow.

● LIVE

[ interactive — use the trigger to open ]

npx shadcn@latest add https://okibi.cndr.dev/r/dialog.json

Installation

Install the theme first, then add the component:

npx shadcn@latest add https://okibi.cndr.dev/r/dialog.json

Install the required dependencies:

npm install @radix-ui/react-dialog lucide-react

Copy the source from the Code tab above into components/ui/dialog.tsx. It uses the cn helper and the okibi theme tokens — install the theme first if you haven't.

Usage

import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"

<Dialog>
  <DialogTrigger>Edit Channel</DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Edit Channel</DialogTitle>
      <DialogDescription>Re-key the relay on SEC // 0x4A2.</DialogDescription>
    </DialogHeader>
  </DialogContent>
</Dialog>

Anatomy

<Dialog>
  <DialogTrigger>Edit Channel</DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Edit Channel</DialogTitle>
      <DialogDescription>Re-key the relay on SEC // 0x4A2.</DialogDescription>
    </DialogHeader>
    <DialogFooter>
      <DialogClose>Cancel</DialogClose>
    </DialogFooter>
  </DialogContent>
</Dialog>

Examples

Form

Drop fielded rows into the body and dock the actions in DialogFooter; DialogClose dismisses on cancel or save.

● LIVE

[ interactive — use the trigger to open ]

Destructive confirm

A confirm dialog for an irreversible action: a hazard-variant confirm button beside a DialogClose cancel.

● LIVE

[ interactive — use the trigger to open ]

Scrolling content

Long bodies scroll inside the panel while the header and footer stay pinned.

● LIVE

[ interactive — use the trigger to open ]

Controlled

Own the open state with open + onOpenChange — open from an out-of-tree button and close programmatically after a confirm action.

● LIVE
[ no preview registered for "dialog-controlled" ]

Accessibility

  • Built on Radix Dialog, so the focus trap, focus restore on close, Esc-to-dismiss, and overlay-click dismiss come for free.
  • A DialogTitle is required — it labels the dialog via aria-labelledby; Radix warns when it's missing.
  • Include DialogDescription to wire the body via aria-describedby; if you omit it, pass aria-describedby={undefined} on DialogContent to silence the warning.
  • The four corner-bracket reticles are decorative — they're aria-hidden and pointer-events-none.
  • The close (X) control rendered by showCloseButton carries an sr-only 'Close' label and a 44px pointer hit area (an invisible before:-inset-2 overlay) per WCAG 2.5.5.

Guidelines

Do

  • Always render a DialogTitle, even if you visually hide it, so the modal is named.
  • Keep DialogDescription in the body to give the dialog an aria-describedby target.
  • Reserve right-edge gutter for a long DialogTitle so it doesn't run under the close button.

Don't

  • Don't drop DialogTitle — the dialog loses its accessible name and Radix warns.
  • Don't set showCloseButton={false} without providing another obvious, labeled dismiss.
  • Don't soften the hard offset shadow or the border-border-strong double border — the sharp HUD modal is intentional.

On this page