Dialog

Modal dialog component built on Radix Dialog. Use it for confirmations, forms, and focused tasks.

The Dialog component renders a modal overlay that traps focus and requires an explicit close. It is built on Radix UI Dialog and styled with PyColors tokens (bg-card, border-border, text-card-foreground).

Use Dialog for:

  • Confirmations (delete, sign out)
  • Forms (edit profile, create project)
  • Focused tasks that shouldn’t leave the current context

Import

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

Basic usage

<Dialog>
  <DialogTrigger asChild>
    <Button variant="outline" size="sm">Open dialog</Button>
  </DialogTrigger>

  <DialogContent>
    <DialogHeader>
      <DialogTitle>Edit profile</DialogTitle>
      <DialogDescription>Update your account details.</DialogDescription>
    </DialogHeader>

    <div className="mt-4">...</div>

    <DialogFooter>
      <DialogClose asChild>
        <Button variant="secondary">Cancel</Button>
      </DialogClose>
      <Button>Save</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>
import {
  Dialog,
  DialogTrigger,
  DialogContent,
  DialogHeader,
  DialogFooter,
  DialogTitle,
  DialogDescription,
  DialogClose,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";

export function EditProfileDialog() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button variant="outline" size="sm">
          Open dialog
        </Button>
      </DialogTrigger>

      <DialogContent>
        <DialogHeader>
          <DialogTitle>Edit profile</DialogTitle>
          <DialogDescription>Update your account details. Changes are saved on submit.</DialogDescription>
        </DialogHeader>

        <div className="mt-4 grid gap-3">
          <Input label="Name" placeholder="Patrice" />
          <Input label="Email" placeholder="patrice@pycolors.com" />
        </div>

        <DialogFooter>
          <DialogClose asChild>
            <Button variant="secondary">Cancel</Button>
          </DialogClose>
          <Button>Save</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

With destructive confirmation

Use a dialog for irreversible actions. Pair DialogClose with the cancel button, and keep the destructive action explicit.

<Dialog>
  <DialogTrigger asChild>
    <Button variant="destructive" size="sm">Delete…</Button>
  </DialogTrigger>

  <DialogContent>
    <DialogHeader>
      <DialogTitle>Delete project</DialogTitle>
      <DialogDescription>This action can’t be undone.</DialogDescription>
    </DialogHeader>

    <DialogFooter>
      <DialogClose asChild>
        <Button variant="secondary">Cancel</Button>
      </DialogClose>
      <Button variant="destructive">Delete</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>
import {
  Dialog,
  DialogTrigger,
  DialogContent,
  DialogHeader,
  DialogFooter,
  DialogTitle,
  DialogDescription,
  DialogClose,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";

export function DeleteDialog() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button variant="destructive" size="sm">
          Delete…
        </Button>
      </DialogTrigger>

      <DialogContent>
        <DialogHeader>
          <DialogTitle>Delete project</DialogTitle>
          <DialogDescription>
            This action can’t be undone. This will permanently delete the project and its data.
          </DialogDescription>
        </DialogHeader>

        <DialogFooter>
          <DialogClose asChild>
            <Button variant="secondary">Cancel</Button>
          </DialogClose>
          <Button variant="destructive">Delete</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

API

Components

ComponentDescription
DialogRoot container (Radix DialogPrimitive.Root)
DialogTriggerTrigger element (use asChild for custom triggers)
DialogContentModal surface + overlay + close button
DialogHeaderTitle/description stack helper
DialogFooterAction row helper (responsive alignment)
DialogTitleDialog title (Radix Title)
DialogDescriptionSupporting text (Radix Description)
DialogCloseClose control (use asChild to wrap a button)

Props

All components extend their respective Radix props.


Accessibility

  • Radix handles focus trapping and restores focus to the trigger on close.
  • Ensure the dialog has a clear title (DialogTitle) and (ideally) a short description.
  • Avoid nesting dialogs. For multi-step flows, consider a Sheet or a full page.
  • Keep one primary action and one secondary action in the footer.

Design guidelines

  • Keep dialog content focused: one task per dialog.
  • Prefer max-w-lg for forms; avoid very wide dialogs.
  • For complex navigation or long content, use Sheet instead.
  • Put destructive actions last and style them clearly.