Dialog

A modal window overlaid on the page with backdrop, focus trap, and keyboard support. Built on bits-ui.

Component Source

View the source code for the dialog component.

$lib/components/ui/dialog/dialog-content.svelte

Installation

npx nnuikit add dialog

# Dialog uses bits-ui under the hood
# Also add button for trigger/actions
npx nnuikit add button
import * as Dialog from "$lib/components/ui/dialog";
import Button from "$lib/components/ui/button/button.svelte";

Quick Start

<Dialog.Root>
  <Dialog.Trigger>
    <Button variant="primary">Open Dialog</Button>
  </Dialog.Trigger>
  <Dialog.Content>
    <Dialog.Header>
      <Dialog.Title>Dialog Title</Dialog.Title>
      <Dialog.Description>
        A short description of what this dialog does.
      </Dialog.Description>
    </Dialog.Header>
    <div class="py-5">
      <p>Your content goes here.</p>
    </div>
    <Dialog.Footer>
      <Dialog.Close>
        <Button variant="tertiary">Cancel</Button>
      </Dialog.Close>
      <Button variant="primary">Confirm</Button>
    </Dialog.Footer>
  </Dialog.Content>
</Dialog.Root>

Interactive Playground

Toggle options and see the generated code.

Close button: visible

Options
<script lang="ts">
  import * as Dialog from "$lib/components/ui/dialog";
  import Button from "$lib/components/ui/button/button.svelte";
</script>

<Dialog.Root>
  <Dialog.Trigger>
    <Button>Open Dialog</Button>
  </Dialog.Trigger>
  <Dialog.Content>
    <Dialog.Header>
      <Dialog.Title>Edit Profile</Dialog.Title>
      <Dialog.Description>
        Make changes to your profile here.
      </Dialog.Description>
    </Dialog.Header>
    <div class="py-5">
      <!-- Your content here -->
    </div>
    <Dialog.Footer>
      <Dialog.Close>
        <Button variant="tertiary">Cancel</Button>
      </Dialog.Close>
      <Button variant="primary">Save</Button>
    </Dialog.Footer>
  </Dialog.Content>
</Dialog.Root>

Examples

Programmatic control

Use bind:open to open/close the dialog from code.

<script lang="ts">
  let open = $state(false);
</script>

<Button onclick={() => (open = true)}>Open</Button>

<Dialog.Root bind:open>
  <Dialog.Content>
    <Dialog.Header>
      <Dialog.Title>Controlled Dialog</Dialog.Title>
      <Dialog.Description>
        Opened programmatically via state.
      </Dialog.Description>
    </Dialog.Header>
    <Dialog.Footer>
      <Button onclick={() => (open = false)}>Close</Button>
    </Dialog.Footer>
  </Dialog.Content>
</Dialog.Root>

Form dialog

A common pattern — form inputs inside a dialog with cancel/save actions.

<Dialog.Root>
  <Dialog.Trigger>
    <Button>Edit Profile</Button>
  </Dialog.Trigger>
  <Dialog.Content>
    <Dialog.Header>
      <Dialog.Title>Edit Profile</Dialog.Title>
      <Dialog.Description>
        Update your name and email below.
      </Dialog.Description>
    </Dialog.Header>
    <form class="flex flex-col gap-4 py-5">
      <div class="flex flex-col gap-1.5">
        <label class="text-sm font-medium">Name</label>
        <Input placeholder="John Doe" />
      </div>
      <div class="flex flex-col gap-1.5">
        <label class="text-sm font-medium">Email</label>
        <Input type="email" placeholder="john@example.com" />
      </div>
    </form>
    <Dialog.Footer>
      <Dialog.Close>
        <Button variant="tertiary">Cancel</Button>
      </Dialog.Close>
      <Button variant="primary">Save Changes</Button>
    </Dialog.Footer>
  </Dialog.Content>
</Dialog.Root>

Accessibility

Focus trap: focus is locked inside the dialog when open
Keyboard: Escape closes the dialog
Click outside: clicking the overlay dismisses the dialog
ARIA: role="dialog", aria-modal="true", aria-labelledby linked to title
Screen reader: title and description are announced on open
Focus restore: focus returns to the trigger element on close

API Reference

Dialog.Content

The modal panel — only prop you typically customize.

PropTypeDefaultDescription
showCloseButton booleantrueShow/hide the close (X) button in the top corner.
class string""Additional CSS classes for the content container.
portalProps PortalProps-Props passed to the underlying Portal component.

Sub-components

ComponentDescription
Dialog.RootContainer that manages open/close state. Accepts open and onOpenChange props.
Dialog.TriggerWraps the element that opens the dialog on click.
Dialog.ContentThe modal panel. Renders inside a portal with overlay and focus trap.
Dialog.HeaderSemantic header area for title and description.
Dialog.TitleThe dialog's heading. Required for accessibility.
Dialog.DescriptionSupporting text below the title.
Dialog.FooterAction area at the bottom for buttons.
Dialog.CloseWraps a button that closes the dialog on click.
Dialog.OverlayBackdrop overlay. Rendered automatically by Content.

Built on bits-ui — Dialog uses Dialog from bits-ui for focus trapping, portal rendering, and ARIA attributes. For the full primitive API (animations, forceMount, etc.), see the bits-ui Dialog docs.