Components

A centered modal dialog — a token-styled wrapper over Base UI's Dialog. Dialog is the state root (open, defaultOpen, onOpenChange, modal); the trigger and close buttons render your element via Base UI's render prop, so a Button stays a full Button — the dialog never mirrors its API.

Install

npx shadcn@latest add @alix/dialog

Preview

Usage

<Dialog>
  <DialogTrigger render={<Button>New</Button>} />
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Create project</DialogTitle>
      <DialogDescription>Give it a name to get started.</DialogDescription>
    </DialogHeader>
    <Field label="Name">
      <Input />
    </Field>
    <DialogFooter>
      <DialogClose render={<Button variant="outline">Cancel</Button>} />
      <Button onClick={() => save()}>Create</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>

Examples

01

Destructive confirmation

Use a dialog when a destructive action needs explicit review before it runs.

<Dialog>
  <DialogTrigger render={<Button variant="destructive">Remove access</Button>} />
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Remove workspace access?</DialogTitle>
      <DialogDescription>
        This person will lose access to engagement files and decision notes immediately.
      </DialogDescription>
    </DialogHeader>
    <DialogFooter>
      <DialogClose render={<Button variant="outline">Cancel</Button>} />
      <DialogClose render={<Button variant="destructive">Remove access</Button>} />
    </DialogFooter>
  </DialogContent>
</Dialog>
02

Engagement form

Field, Input, Select, and Textarea compose inside the modal body while DialogFooter owns action placement.

<Dialog>
  <DialogTrigger render={<Button>New engagement</Button>} />
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Create engagement</DialogTitle>
      <DialogDescription>Add the basic workspace details before inviting the team.</DialogDescription>
    </DialogHeader>
    <div className="grid gap-4">
      <Field label="Engagement name" required>
        <Input placeholder="e.g. Project Atlas" />
      </Field>
      <Field label="Capability">
        <Select
          placeholder="Select capability"
          items={[
            { value: "turnaround", label: "Turnaround" },
            { value: "transactions", label: "Transactions" },
          ]}
        />
      </Field>
      <Field label="Context">
        <Textarea rows={3} placeholder="Summarise the client need." />
      </Field>
    </div>
    <DialogFooter>
      <DialogClose render={<Button variant="outline">Cancel</Button>} />
      <DialogClose render={<Button>Create engagement</Button>} />
    </DialogFooter>
  </DialogContent>
</Dialog>
03

Review summary

A wider dialog can hold a concise decision summary with status badges and a two-action ButtonGroup.

<Dialog>
  <DialogTrigger render={<Button variant="outline">Review summary</Button>} />
  <DialogContent className="max-w-2xl">
    <DialogHeader>
      <DialogTitle>Board update summary</DialogTitle>
      <DialogDescription>Confirm the key points before the client-facing version is sent.</DialogDescription>
    </DialogHeader>
    <div className="grid gap-3 text-sm">
      <div className="flex items-center justify-between gap-4 border border-border p-3">
        <span>Liquidity forecast</span>
        <Badge variant="success" dot>Ready</Badge>
      </div>
      <div className="flex items-center justify-between gap-4 border border-border p-3">
        <span>Stakeholder actions</span>
        <Badge variant="warning" dot>Needs review</Badge>
      </div>
    </div>
    <DialogFooter>
      <ButtonGroup
        primaryAction={<DialogClose render={<Button>Send update</Button>} />}
        secondaryAction={<DialogClose render={<Button variant="outline">Keep editing</Button>} />}
      />
    </DialogFooter>
  </DialogContent>
</Dialog>

When to use it

Use it for

  • Blocking decisions that need focus before the user returns to the page.
  • Short create/edit flows with a title, description, fields, and explicit footer actions.
  • Destructive confirmations where the consequence needs readable context.

Reach for something else

  • Large side panels or filters that should preserve page context — use Drawer instead.
  • Anchored helper content tied to one trigger — use Popover instead.
  • Transient success or failure messages after an action completes — use Toast instead.
  • Overflow command lists — use Menu instead.

Props

PropTypeDefaultDescription
Dialogopen?, defaultOpen?, onOpenChange?, modal?The state root (Base UI's Dialog.Root). Controls open/close state.
DialogTrigger / DialogCloserender: ReactElementOpen/close the dialog. They render your element via the render prop, so a Button keeps its full API rather than the dialog re-modelling it.
DialogContentchildrenThe portalled scrim + centered popup. Drop a header, body, and footer inside; a top-right close button is included automatically.
DialogHeader / DialogTitle / DialogDescription / DialogFooterchildrenStructural slots: title + description region, and a right-aligned action row that stacks on mobile.

See also