Dialog

A modal that stops the page for one question.

Overview

A confirmation or a short form the reader must answer before they go on.

Confirm

Do
import { useState } from "react";
import { Button, Dialog } from "@hackcove/ui";

function Example() {
  const [open, setOpen] = useState(false);
  return (
    <>
      <Button variant="outline" onClick={() => setOpen(true)}>
        Delete build
      </Button>
      {open && (
        <Dialog
          title="Delete build"
          description="This removes the build and every snapshot in it."
          onClose={() => setOpen(false)}
          footer={
            <>
              <Button variant="ghost" onClick={() => setOpen(false)}>
                Cancel
              </Button>
              <Button tone="danger" onClick={() => setOpen(false)}>
                Delete
              </Button>
            </>
          }
        />
      )}
    </>
  );
}
A confirmation is a title that names the action, one line of consequence, and Cancel beside the action. It is rendered only while open.
Don't
import { useState } from "react";
import { Button, Dialog } from "@hackcove/ui";

function Example() {
  const [open, setOpen] = useState(false);
  return (
    <>
      <Button variant="outline" onClick={() => setOpen(true)}>
        Delete build
      </Button>
      {open && (
        <Dialog
          title="Are you sure?"
          onClose={() => setOpen(false)}
          footer={
            <Button tone="danger" onClick={() => setOpen(false)}>
              Delete
            </Button>
          }
        />
      )}
    </>
  );
}
With no Cancel and no consequence, the only way out of the dialog is the one button that destroys the build.

Notice

Do
Your review is saved.
import { Button, Callout, Stack } from "@hackcove/ui";

<Stack gap="sm">
  <Button variant="outline">Save</Button>
  <Callout tone="positive">Your review is saved.</Callout>
</Stack>
A result that needs no answer is a Callout in the page, where it does not take the page away.
Don't
import { useState } from "react";
import { Button, Dialog } from "@hackcove/ui";

function Example() {
  const [open, setOpen] = useState(false);
  return (
    <>
      <Button variant="outline" onClick={() => setOpen(true)}>
        Save
      </Button>
      {open && (
        <Dialog
          title="Saved"
          description="Your review is saved."
          onClose={() => setOpen(false)}
          footer={<Button onClick={() => setOpen(false)}>OK</Button>}
        />
      )}
    </>
  );
}
A modal for a message makes the reader dismiss it before they can carry on.

Usage

  • Render it only while it is open: {open && <Dialog … onClose={() => setOpen(false)} />}. It opens itself on mount.
  • A title that names the action, a description with the consequence, and the actions in footer: Cancel as variant="ghost" first, then the one action, tone="danger" when it destroys something.
  • size="sm" is a short list; md, the default, holds a form. A submit button in the footer reaches a form in the body with its form attribute.
  • One text field is a FieldDialog. A record or a long form is a Drawer. A message that needs no answer is a Callout.

Accessibility

  • A Dialog is the browser's own <dialog> opened with showModal(): the page behind goes inert, focus stays inside it and Esc closes it.
  • It is named by its title, an h2, through aria-labelledby.
  • A click on the backdrop closes it, and so does a submit of a <form method="dialog">; every close calls onClose.
  • The browser focuses the first focusable element in it when it opens; put autoFocus on the button that should have focus first.

API

Dialog

A modal on the browser's own <dialog>: it is opened with showModal() on mount, so render it only while it is open. The page behind goes inert, Esc closes it and focus stays inside; a click on the backdrop (the <dialog> element itself, not its contents) closes it too.


description
Type
ReactNode

footer

Actions under the body, right-aligned. A submit button here can reach a form in the body with its form attribute.

Type
ReactNode

onClose required

Called when the dialog closes: Esc, a click on the backdrop, or a <form method="dialog"> submit.

Type
() => void

size

sm is a list; md (the default) holds a form.

Type
"sm" | "md"
Default
md

title required

The dialog's accessible name, shown as its heading.

Type
ReactNode