Skip to content

Pickers and overlays

Dialog

A modal layer that asks people to finish or dismiss a focused task.

When to use it: Use it for work that should temporarily block the page behind it.

On this page

Example

Ready to publish?

This dialog is scoped to this example.

Dialog.tsxtsx
import { Button, Dialog, DialogContent, DialogTrigger } from "@comp0/react";

export function Example() {
  return (
    <Dialog>
      <DialogTrigger className="rounded bg-teal-700 px-3 py-2.5 text-base text-white sm:py-2 sm:text-sm dark:bg-teal-400 dark:text-zinc-950">
        Open dialog
      </DialogTrigger>
      <DialogContent
        aria-label="Example dialog"
        className="m-auto w-[min(24rem,calc(100vw-2rem))] translate-y-0 rounded-[min(1vw,12px)] bg-white p-4 text-zinc-900 opacity-100 shadow-2xl ring-1 ring-zinc-950/10 transition-[opacity,translate] duration-150 ease-out starting:translate-y-1 starting:opacity-0 motion-reduce:transition-none backdrop:bg-zinc-950/40 dark:bg-zinc-900 dark:text-zinc-50 dark:shadow-none dark:ring-white/10"
      >
        <div className="flex flex-col gap-2">
          <p className="text-base font-medium sm:text-sm">Ready to publish?</p>
          <p className="text-base text-zinc-600 sm:text-sm dark:text-zinc-400">
            This dialog is scoped to this example.
          </p>
          <form method="dialog" className="flex pt-2">
            <Button
              className="rounded bg-teal-700 px-3 py-2.5 text-base text-white sm:py-2 sm:text-sm dark:bg-teal-400 dark:text-zinc-950"
              type="submit"
            >
              Done
            </Button>
          </form>
        </div>
      </DialogContent>
    </Dialog>
  );
}

Anatomy

Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.

A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.

  1. Dialog

    Modal open-state provider. Does not add a DOM element.

  2. DialogTrigger

    Button that opens the dialog. Owns a DOM element.

  3. DialogContent

    Modal dialog element. Owns a DOM element.

Step by step

  1. 1

    Add the main part

    Start Dialog with DialogTrigger.

  2. 2

    Add the supporting parts

    Put a labelled DialogContent after the trigger.

  3. 3

    Make the behavior clear

    Keep a clear close or finish action inside the content.

    Exampletsx
    <Dialog><DialogTrigger>Open details</DialogTrigger><DialogContent aria-label="Details">Details</DialogContent></Dialog>

Keyboard

Esc
Closes and restores trigger focus.
Cycles inside the modal.

Forms and accessibility

No native form behavior; forms may live inside DialogContent.

Accessibility checklist

  • Give DialogContent an accessible name.
  • Keep focus inside the modal until it closes.
  • Include a clear way to finish or dismiss the task.

API reference

Importtsx
import { Dialog, DialogContent, DialogTrigger } from "@comp0/react";

Dialog

Context only

Modal open-state provider.

PropTypeDescription
open / defaultOpenbooleanControlled or initial open state.
onToggle(open: boolean) => voidReceives the next open state.

DialogTrigger

DOM element

Button that opens the dialog.

PropTypeDescription
asElementType | FragmentFragment merges the trigger onto your own element child.

DialogContent

DOM element

Modal dialog element.

PropTypeDescription
aria-labelstringAccessible name for the dialog task.
portalbooleanRenders into document.body; on by default.
closedby"any" | "closerequest" | "none"Native dismissal policy; any adds light dismiss where supported.
onClose(event) => voidNative dialog close event.

Style hooks

Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.

[data-open]

on DialogTrigger, DialogContent

The dialog is open.
:open

on DialogContent

Native pseudo-class equivalent.

Keep exploring