LOKE Design System
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 DialogHeader and DialogFooter for consistent layout.
  • The DialogDescription provides additional context for screen readers.
  • Use asChild on DialogTrigger to 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 DialogTitle for accessibility.
  • Use DialogDescription to provide additional context.
  • Keep dialog content focused and concise.
  • Provide clear actions (save, cancel, close) in the footer.
  • Consider using AlertDialog for destructive actions that need confirmation.
  • Use controlled mode (open prop) when you need to programmatically control the dialog.
  • For long content, add overflow-y-auto and max-h-[80vh] to DialogContent.