Overlays

Dialog

Modal dialog in three sizes with title, description and a footer of actions. Fills the width on phones and scrolls inside.

Installation

Install the package (React 19):

terminal
npm install @krackedui/motion

Import the styles once, in your app entry or root layout:

/src/main.tsx
import '@krackedui/motion/styles.css';

Use it anywhere inside your app's <Theme> (see Installation):

/src/DialogExample.tsx
import { Button, Dialog, TextInput } from '@krackedui/motion';

export function EditProfile() {
  return (
    <Dialog.Root>
      <Dialog.Trigger asChild>
        <Button variant="secondary">Edit profile</Button>
      </Dialog.Trigger>
      <Dialog.Content size="sm">
        <Dialog.Title>Edit profile</Dialog.Title>
        <Dialog.Description>Your name is shown on pages you edit.</Dialog.Description>
        <TextInput aria-label="Name" defaultValue="Ada Lovelace" className="mt-2" />
        <Dialog.Footer>
          <Dialog.Close asChild><Button variant="secondary">Cancel</Button></Dialog.Close>
          <Dialog.Close asChild><Button variant="primary">Save</Button></Dialog.Close>
        </Dialog.Footer>
      </Dialog.Content>
    </Dialog.Root>
  );
}

Examples

Form dialog

Controlled, long content

size="lg"; the body scrolls inside the panel.

Static surface

Static dialog
The dialog card without overlay or focus handling.

Composition

anatomy.tsx
<Dialog.Root>
  <Dialog.Trigger asChild>…</Dialog.Trigger>
  <Dialog.Content size="md">
    <Dialog.Title />
    <Dialog.Description />
    …
    <Dialog.Footer>
      <Dialog.Close asChild>…</Dialog.Close>
    </Dialog.Footer>
  </Dialog.Content>
</Dialog.Root>
  • Dialog.Content renders the overlay and the portal for you.
  • DialogSurface / DialogOverlay are the static look for previews.

API Reference

Dialog.Root

Holds the open state.

PropTypeDefault
open
boolean
defaultOpen
boolean
false
onOpenChange
(open: boolean) => void
modal
boolean
true

Dialog.Trigger

Opens the dialog.

PropTypeDefault
asChild
boolean
false

Dialog.Content

The panel, with the overlay and portal. Padding 24 (20 on phones), flex column with 8px gaps.

PropTypeDefault
size
"sm""md""lg"
"md"
width
number
height
number
top
number
radius
"md""xl"
"md"
onOpenAutoFocus
(event: Event) => void
onCloseAutoFocus
(event: Event) => void
onEscapeKeyDown
(event: KeyboardEvent) => void
onPointerDownOutside
(event: PointerDownOutsideEvent) => void

Accessible name (16/600), description (14 secondary) and the action row (right-aligned, stacked on phones).

PropTypeDefault
className
string

Dialog.Close

Closes the dialog.

PropTypeDefault
asChild
boolean
false

DialogOverlay

The dimmed underlay on its own (no portal or behavior), for static renders behind a DialogSurface. A <div>: all its props pass through.

PropTypeDefault
className
string

DialogSurface

Static dialog card (never wider than its container).

PropTypeDefault
size
"sm""md""lg"
width
number
height
number
radius
"md""xl"
"md"

Accessibility

  • Follows the WAI-ARIA modal dialog pattern: role="dialog", aria-modal, named by Dialog.Title and described by Dialog.Description.
  • A Dialog.Title is required (a development warning names a dialog without one). Without a description pass aria-describedby={undefined} to Content.
  • Focus moves into the dialog on open and is trapped there; Tab / Shift+Tab cycle through its controls.
  • Escape or an overlay click closes it; focus returns to the element that opened it.
  • The page behind is inert and does not scroll while open.
  • Under 640px the panel fills the width minus 8px margins; content taller than the screen scrolls inside the panel. Opens and closes with the shared motion layer (styles/motion.css); with prefers-reduced-motion: reduce it only fades.

Usage

  • Use for a focused task that blocks the page: editing a record, a short form, a decision.
  • Use ConfirmDialog for a yes/no decision about a consequential action.
  • Use Popover for small inline edits, Sheet for side panels and long forms.
  • Keep the primary action last in Dialog.Footer (it is on top on phones).
© 2026 Motion. Internal documentation.