Components
Dialog
A modal dialog that interrupts the user with important content and expects a response.
Dialog
The Dialog component displays content in a modal overlay that requires user interaction. It interrupts the current task to focus attention on important information or actions that need immediate response.
Dialog automatically handles focus trapping, scroll locking, and accessibility. Always include a DialogTitle for screen readers.
Features
- Modal overlay with backdrop
- Automatic focus trapping and restoration
- Scroll lock when open
- Keyboard accessible (Escape to close)
- Controlled and uncontrolled modes
- Customizable close button
- Animated enter/exit transitions
- Proper ARIA attributes
Usage
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogFooter,
} from '@loke/design-system/dialog';
export default function Example() {
return (
<Dialog>
<DialogTrigger asChild>
<Button>Open Dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription>
This is the dialog description.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button>Save changes</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}Tips:
- Use
DialogHeaderandDialogFooterfor consistent layout. - The
DialogDescriptionprovides additional context for screen readers. - Use
asChildonDialogTriggerto use your own button component.
Props
Dialog
Prop
Type
DialogContent
Prop
Type
DialogTrigger
Prop
Type
Examples
Basic dialog
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Edit Profile</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Edit profile</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when you're done.
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">Name</Label>
<Input id="name" defaultValue="Pedro Duarte" className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="username" className="text-right">Username</Label>
<Input id="username" defaultValue="@peduarte" className="col-span-3" />
</div>
</div>
<DialogFooter>
<Button type="submit">Save changes</Button>
</DialogFooter>
</DialogContent>
</Dialog>Dialog with form
const [open, setOpen] = useState(false);
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button>Subscribe</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Subscribe to newsletter</DialogTitle>
<DialogDescription>
Enter your email to receive updates.
</DialogDescription>
</DialogHeader>
<form onSubmit={(e) => {
e.preventDefault();
// Handle form submission
setOpen(false);
}}>
<div className="py-4">
<Input type="email" placeholder="you@example.com" />
</div>
<DialogFooter>
<Button type="submit">Subscribe</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>Custom close behavior
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Open Settings</Button>
</DialogTrigger>
<DialogContent showCloseButton={false}>
<DialogHeader>
<DialogTitle>Settings</DialogTitle>
<DialogDescription>
Configure your preferences below.
</DialogDescription>
</DialogHeader>
<div className="py-4">
<p className="text-sm text-muted-foreground">
This dialog has a custom close button in the footer.
</p>
</div>
<DialogFooter>
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button>Save</Button>
</DialogFooter>
</DialogContent>
</Dialog>Scrollable content
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Terms of Service</Button>
</DialogTrigger>
<DialogContent className="max-h-[80vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>Terms of Service</DialogTitle>
<DialogDescription>
Please read our terms of service carefully.
</DialogDescription>
</DialogHeader>
<div className="py-4 space-y-4">
{/* Long content here */}
</div>
<DialogFooter>
<Button>I Accept</Button>
</DialogFooter>
</DialogContent>
</Dialog>Alert dialog style
<Dialog>
<DialogTrigger asChild>
<Button variant="destructive">Delete Account</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you absolutely sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete your
account and remove your data from our servers.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button variant="destructive">Delete</Button>
</DialogFooter>
</DialogContent>
</Dialog>Accessibility
- Uses
role="dialog"with proper ARIA attributes. - Focus is automatically trapped within the dialog when open.
- Focus returns to the trigger element when closed.
- Escape key closes the dialog.
- DialogTitle is linked via
aria-labelledby. - DialogDescription is linked via
aria-describedby. - Background content is hidden from screen readers with
aria-hidden.
Best practices
- Always include a
DialogTitlefor accessibility. - Use
DialogDescriptionto provide additional context. - Keep dialog content focused and concise.
- Provide clear actions (save, cancel, close) in the footer.
- Consider using
AlertDialogfor destructive actions that need confirmation. - Use controlled mode (
openprop) when you need to programmatically control the dialog. - For long content, add
overflow-y-autoandmax-h-[80vh]toDialogContent.