ComponentsDialog
Dialog
Open a focused window above the page for a task or confirmation.
On this page
Use this component from the local workspace package. Follow the setup guide first. A public npm package and registry are not available yet.
View registry filesImport the component into your page or component file.
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@dethink/components";
export function Example() {
return (
<Dialog>
<DialogTrigger>View details</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Project details</DialogTitle>
<DialogDescription>Review your project settings.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose>Done</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}Try the examples, then open the code to use them in your app. Open a dialog and Tab around — focus stays inside until it closes.
Basic
Use DialogTrigger to open the dialog and DialogClose to close it. Always include a DialogTitle.
Show sourceexamples/dialog/basic.tsx
"use client";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@dethink/components";
export function DialogBasic() {
return (
<div className="flex justify-center">
<Dialog>
<DialogTrigger>Workspace settings</DialogTrigger>
<DialogContent dismissible size="sm">
<DialogHeader>
<DialogTitle>Workspace settings</DialogTitle>
<DialogDescription>
Changes apply to every dashboard in this workspace.
</DialogDescription>
</DialogHeader>
<div className="px-[var(--dt-space-6)] py-[var(--dt-space-3)] text-sm">
Focus is trapped inside; Escape or the backdrop dismisses, and focus
returns to the trigger.
</div>
<DialogFooter>
<DialogClose variant="outline">Cancel</DialogClose>
<DialogClose variant="solid">Save changes</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
);
}Alert dialog
Ask users to confirm an action. Clicking outside this dialog does not close it.
Show sourceexamples/dialog/alert.tsx
"use client";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@dethink/components";
export function DialogAlert() {
return (
<div className="flex justify-center">
<AlertDialog>
<AlertDialogTrigger variant="destructive">
Revoke all sessions
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Revoke all sessions?</AlertDialogTitle>
<AlertDialogDescription>
Every device is signed out immediately, including this one.
AlertDialog blocks backdrop dismissal so the choice is explicit.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Keep sessions</AlertDialogCancel>
<AlertDialogAction variant="destructive">
Revoke everything
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div>
);
}Examples that combine components for common tasks.
Multi-step wizard
Split a task into three steps. Back and Continue move between steps; closing the dialog resets the form.
Show sourceexamples/dialog/recipe-wizard.tsx
"use client";
import { useState } from "react";
import {
Button,
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
Field,
FieldControl,
FieldLabel,
Input,
Select,
SelectItem,
} from "@dethink/components";
const steps = ["Name", "Region", "Review"] as const;
/**
* A controlled Dialog hosting a multi-step flow: the dialog stays open
* across steps, Back/Continue drive the index, and the flow resets whenever
* the dialog closes so reopening starts clean.
*/
export function DialogRecipeWizard() {
const [open, setOpen] = useState(false);
const [step, setStep] = useState(0);
const [name, setName] = useState("");
const [region, setRegion] = useState("");
const isLast = step === steps.length - 1;
return (
<div className="flex justify-center">
<Dialog
open={open}
onOpenChange={(next) => {
setOpen(next);
if (!next) {
setStep(0);
}
}}
>
<DialogTrigger>New project…</DialogTrigger>
<DialogContent size="sm">
<DialogHeader>
<DialogTitle>New project — {steps[step]}</DialogTitle>
<DialogDescription>
Step {step + 1} of {steps.length}
</DialogDescription>
</DialogHeader>
<div className="px-[var(--dt-space-6)] py-[var(--dt-space-3)]">
{step === 0 ? (
<Field id="wiz-name">
<FieldLabel>Project name</FieldLabel>
<FieldControl asChild>
<Input
value={name}
onChange={(event) => setName(event.target.value)}
placeholder="apollo"
/>
</FieldControl>
</Field>
) : step === 1 ? (
<Select
label="Region"
placeholder="Choose a region"
value={region || undefined}
onValueChange={setRegion}
>
<SelectItem value="us-east">US East</SelectItem>
<SelectItem value="eu-west">EU West</SelectItem>
</Select>
) : (
<dl className="space-y-1 text-sm">
<div className="flex justify-between">
<dt className="text-muted-foreground">Name</dt>
<dd>{name || "—"}</dd>
</div>
<div className="flex justify-between">
<dt className="text-muted-foreground">Region</dt>
<dd>{region || "—"}</dd>
</div>
</dl>
)}
</div>
<DialogFooter>
<Button
variant="outline"
disabled={step === 0}
onClick={() => setStep(step - 1)}
>
Back
</Button>
<Button
onClick={() => {
if (isLast) {
setOpen(false);
setStep(0);
} else {
setStep(step + 1);
}
}}
>
{isLast ? "Create project" : "Continue"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
);
}Type-to-confirm deletion
Require users to type the project name before enabling Delete.
Show sourceexamples/dialog/recipe-type-to-confirm.tsx
"use client";
import { useState } from "react";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
Field,
FieldControl,
FieldLabel,
Input,
} from "@dethink/components";
const PROJECT = "apollo-prod";
/**
* Destructive confirmation that cannot be clicked through on autopilot:
* the action stays disabled until the typed name matches exactly, and
* closing resets the input.
*/
export function DialogRecipeTypeToConfirm() {
const [typed, setTyped] = useState("");
const confirmed = typed === PROJECT;
return (
<div className="flex justify-center">
<AlertDialog onOpenChange={(open) => !open && setTyped("")}>
<AlertDialogTrigger variant="destructive">
Delete project…
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete {PROJECT}?</AlertDialogTitle>
<AlertDialogDescription>
This permanently deletes the project, its deployments, and all
request logs. Type the project name to confirm.
</AlertDialogDescription>
</AlertDialogHeader>
<div className="px-[var(--dt-space-6)] py-[var(--dt-space-2)]">
<Field id="del-confirm">
<FieldLabel>
Type <span className="font-mono">{PROJECT}</span> to continue
</FieldLabel>
<FieldControl asChild>
<Input
autoComplete="off"
value={typed}
onChange={(event) => setTyped(event.target.value)}
/>
</FieldControl>
</Field>
</div>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction variant="destructive" isDisabled={!confirmed}>
Delete forever
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div>
);
}Set open state on Dialog. Set width and closing behavior on DialogContent.
| Prop | What it does | Default |
|---|---|---|
open / defaultOpen / onOpenChangeboolean / boolean / (open) => void | Use open with onOpenChange to manage the dialog, or defaultOpen to set its starting state. | Not set |
DialogTrigger / DialogClosevariant + size (Button API) | Buttons that open and close the dialog; both accept the Button variant and size props. | Not set |
DialogContent — size"sm" | "md" | "lg" | "xl" | "full" | Sets the dialog width. | "md" |
DialogContent — dismissibleboolean | Whether clicking the backdrop closes the dialog. | false |
DialogContent — keyboardDismissDisabledboolean | Prevents the Escape key from closing the dialog. | false |
DialogContent — scrollBehavior"inside" | "outside" | Whether long content scrolls within the panel or the page. | "inside" |
DialogContent — showCloseButtonboolean | Shows a close button in the corner. | false |
DialogHeader / DialogTitle / DialogDescription / DialogFootersection components | Build the dialog header and footer. The title and description tell screen readers what the dialog is for. | Not set |
| Prop | What it does | Default |
|---|---|---|
AlertDialogsame as Dialog | A confirmation dialog. Clicking outside it does not close it. | Not set |
AlertDialogAction / AlertDialogCancelvariant + size (Button API) | Confirm and cancel buttons; Action supports isDisabled for gated confirmation. | Not set |