Browse Components

Dialog

Focused overlays for information, decisions, and forms.

Basic

A focused message with a clear close action.

A little room to focus.

Keep a focused task in view while the rest of the page takes a step back.

This example also closes when you click the backdrop.

View Code
HTML
<button
  class="btn secondary"
  type="button"
  data-dialog-open="welcome"
  aria-haspopup="dialog"
  aria-controls="welcome"
>
  Simple Dialog
</button>
<dialog
  class="dialog"
  id="welcome"
  aria-labelledby="welcome-title"
  aria-describedby="welcome-description"
  data-dialog-dismiss
>
  <header class="dialog-header">
    <h2 id="welcome-title">
      A little room to focus.
    </h2>
  </header>
  <div class="dialog-body stack">
    <p id="welcome-description">
      Keep a focused task in view while the rest of the page takes a step back.
    </p>
    <p class="muted">
      This example also closes when you click the backdrop.
    </p>
  </div>
  <footer class="dialog-footer">
    <button class="btn" type="button" data-dialog-close autofocus>
      Got It
    </button>
  </footer>
</dialog>

Confirmation

Focus starts on Keep Draft. Backdrop clicks do not dismiss a decision; Escape cancels. No data is discarded.

Discard this draft?

This is a confirmation preview. No draft will be discarded. In your app, explain the consequence before asking someone to continue.

View Code
HTML
<button
  class="btn secondary"
  type="button"
  data-dialog-open="confirm"
  aria-haspopup="dialog"
  aria-controls="confirm"
>
  Confirmation
</button>
<dialog
  class="dialog"
  id="confirm"
  role="alertdialog"
  aria-labelledby="confirm-title"
  aria-describedby="confirm-description"
>
  <header class="dialog-header">
    <h2 id="confirm-title">
      Discard this draft?
    </h2>
  </header>
  <div class="dialog-body">
    <p id="confirm-description">
      This is a confirmation preview. No draft will be discarded. In your app, explain the consequence before asking someone to continue.
    </p>
  </div>
  <form method="dialog">
    <footer class="dialog-footer">
      <button class="btn secondary" value="cancel" autofocus>
        Keep Draft
      </button>
      <button class="btn" value="discard">
        Discard Draft
      </button>
    </footer>
  </form>
</dialog>

Form

Native validation keeps invalid input open. Cancel bypasses validation; backdrop clicks do not discard input. This example does not save data.

Make yourself at home.

Try native validation. This demo closes without saving your changes.

View Code
HTML
<button
  class="btn secondary"
  type="button"
  data-dialog-open="profile"
  aria-haspopup="dialog"
  aria-controls="profile"
>
  Form Dialog
</button>
<dialog
  class="dialog"
  id="profile"
  aria-labelledby="profile-title"
  aria-describedby="profile-description"
>
  <header class="dialog-header">
    <h2 id="profile-title">
      Make yourself at home.
    </h2>
  </header>
  <form method="dialog">
    <div class="dialog-body stack">
      <p id="profile-description" class="muted">
        Try native validation. This demo closes without saving your changes.
      </p>
      <label class="stack">
        Display name
        <input
          class="input"
          name="display-name"
          autocomplete="nickname"
          required
          placeholder="Your name"
          autofocus
        >
      </label>
      <label class="stack">
        Email address
        <input
          class="input"
          type="email"
          name="email"
          autocomplete="email"
          required
          placeholder="[email protected]"
        >
      </label>
    </div>
    <footer class="dialog-footer">
      <button class="btn secondary" type="button" data-dialog-close>
        Cancel
      </button>
      <button class="btn" value="done">
        Done
      </button>
    </footer>
  </form>
</dialog>

Scrolling content

A wider layout with a scrolling body and visible actions.

Space for the whole story.

The body scrolls while the heading and actions stay visible.

One task at a time

Keep the purpose clear. Use a page for a separate destination.

A clear next step

Choose specific labels. Give people a way to cancel.

Every screen

Try a narrow window or larger text. Actions stay within reach.

Keyboard access

Use Tab to move, Escape to close, and return to your starting point.

View Code
HTML
<button
  class="btn secondary"
  type="button"
  data-dialog-open="guide"
  aria-haspopup="dialog"
  aria-controls="guide"
>
  Scrolling Content
</button>
<dialog
  class="dialog dialog-wide"
  id="guide"
  aria-labelledby="guide-title"
  data-dialog-dismiss
>
  <header class="dialog-header">
    <h2 id="guide-title" tabindex="-1" autofocus>
      Space for the whole story.
    </h2>
  </header>
  <div class="dialog-body stack" tabindex="0" aria-label="Example reading content">
    <p>
      The body scrolls while the heading and actions stay visible.
    </p>
    <h3>
      One task at a time
    </h3>
    <p>
      Keep the purpose clear. Use a page for a separate destination.
    </p>
    <h3>
      A clear next step
    </h3>
    <p>
      Choose specific labels. Give people a way to cancel.
    </p>
    <h3>
      Every screen
    </h3>
    <p>
      Try a narrow window or larger text. Actions stay within reach.
    </p>
    <h3>
      Keyboard access
    </h3>
    <p>
      Use Tab to move, Escape to close, and return to your starting point.
    </p>
  </div>
  <footer class="dialog-footer">
    <button class="btn" type="button" data-dialog-close>
      Close
    </button>
  </footer>
</dialog>

Right-to-left

Hebrew content with dir=rtl and lang=he. Layout and actions follow the reading direction.

ברוכים הבאים

זוהי דוגמה לחלון בעברית, מימין לשמאל.

View Code
HTML
<div dir="rtl" lang="he">
  <button class="btn secondary" type="button" data-dialog-open="hebrew">
    פתיחת חלון
  </button>
  <dialog
    class="dialog"
    id="hebrew"
    dir="rtl"
    lang="he"
    aria-labelledby="hebrew-title"
    data-dialog-dismiss
  >
    <header class="dialog-header">
      <h2 id="hebrew-title">
        ברוכים הבאים
      </h2>
    </header>
    <div class="dialog-body">
      <p>
        זוהי דוגמה לחלון בעברית, מימין לשמאל.
      </p>
    </div>
    <footer class="dialog-footer">
      <button class="btn" type="button" data-dialog-close autofocus>
        סגירה
      </button>
    </footer>
  </dialog>
</div>

Installation

Download these files into the matching paths in your project, or use Create to assemble a kit. Include each dependency once. Do not also load app.css.

Add to your page
<link rel="stylesheet" href="/library/assets/base.css">
<link rel="stylesheet" href="/library/assets/button.css">
<link rel="stylesheet" href="/library/assets/field.css">
<link rel="stylesheet" href="/library/assets/dialog.css">
<script defer src="/library/assets/dialog.js"></script>

14,213 bytes CSS including base · 2,172 bytes runtime JavaScript

Usage

Open a focused task

Use dialog.dialog with a visible title linked by aria-labelledby. Connect an opener with data-dialog-open and the dialog’s ID.

Offer a clear way out

Include a close or cancel button. Escape closes the dialog and focus returns to the opener. Use autofocus deliberately, favoring the safe action.

Own the result

Include the dialog script once. Your app handles validation, saving, and errors. Closing a dialog does not mean data was saved.

Building with AI? The AI Manifest has these notes and the full contract. See the AI Guide.

Framework integrations

Use this shared component standalone or through the tested React, Next.js, Vue, Nuxt, Angular, Svelte, and Astro integration paths. Keep application state in your framework; adapters handle native behavior and cleanup.

View Integration APIs and Working Examples. For dialogs, choose either the adapter controller or the standalone initializer, never both on the same element.