Use a dialog when people need to act on information: to confirm a
high-risk action, finish one task, or read the copy that belongs to
that task. The basic and full-screen variants use the same element.
There is no
modal-header, modal-content, or
modal-footer class.
Tokens follow the
M3 dialog spec.
The basic container is surface-container-high, 28dp
corners, 280 to 560dp wide, and elevation 3. The headline is
headline-small / on-surface. Supporting
text is body-medium /
on-surface-variant. Actions are text buttons, end
aligned, with an 8dp gap. Padding is 24dp (16dp between the
headline and the body). The scrim is
--md-comp-scrim-color with a 12px blur. Opening with showModal() also stops
the page behind it from scrolling.
Open it with showModal() and close it with
close(). These are Dialog API methods, not a plugin.
Basic
The <dialog> is the surface and a heading is the
headline. A <p>, or a wrapping
<div>, is supporting text. The last child
<form method="dialog"> or <nav>
is the action row. An optional leading icon centers the headline. Add
an <hr> as the divider when extra content follows
the copy.
<button type="button" onclick="document.getElementById('dialog1').showModal()">
Show
</button>
<dialog id="dialog1" aria-labelledby="basic-dialog-title-title">
<h2 id="basic-dialog-title-title">Basic dialog title</h2>
<p>A dialog is a modal window that appears in front of app content.</p>
<form method="dialog">
<button type="submit" value="cancel">Cancel</button>
<button type="submit" value="accept">Accept</button>
</form>
</dialog>
When someone presses a submit button in a
<form method="dialog">, the browser closes the
dialog and sets dialog.returnValue from the button's
value. Action buttons are text
buttons by default. Add filled, tonal,
or outlined if you need more emphasis. Tapping the
scrim closes it too, but only if the press and the release both
miss the dialog. For docked panes, see
Side sheet
and
Bottom sheet.
Full-screen
Add max when the task needs the whole viewport,
typically on compact windows or whenever the dialog holds a
form. A full-screen dialog has no scrim and no corner radius. A
<header> is the 64dp top bar: a close icon,
a title-large headline, and the confirming text
button. Body content is inset 24dp.
<dialog class="max" aria-labelledby="full-screen-dialog-title-title">
<header>
<button type="button" aria-label="Close" onclick="this.closest('dialog').close()">
<span class="material-symbols" aria-hidden="true">close</span>
</button>
<h2 id="full-screen-dialog-title-title">Full-screen dialog title</h2>
<form method="dialog">
<button type="submit" value="save">Save</button>
</form>
</header>
<div>…</div>
</dialog>
Confirm from script
Expressive.Dialogs.confirm() asks a yes-or-no question
and returns a promise. It builds a basic dialog with
role="alertdialog", opens it with
showModal(), and removes it once it closes. The promise
resolves true when the person picks the confirm button
and false on Cancel, Escape or a scrim tap.
const ok = await Expressive.Dialogs.confirm({
headline: 'Delete draft?',
text: 'The draft and its attachments are removed.',
confirm: 'Delete'
});
if (ok) deleteDraft();
text is the question and is required. headline
is optional. With a headline, the dialog is named by it and described
by the text; without one, the text names it. All four strings are set
as text, so markup in them is shown, not parsed. If page code
removes the open dialog, for example on a route change, the promise
resolves false.
Focus starts on Cancel, the less destructive action, and the browser returns it to the element that had focus before the call. Label the confirm button with the action it takes, such as "Delete" or "Discard", rather than the "OK" default.
confirm and cancel set the button labels for
one call. Expressive.Dialogs.i18n holds the defaults,
{ confirm: 'OK', cancel: 'Cancel' }; assign to it to
change them for every later call. With the modular entry,
confirm() works without Dialogs.Init(), but
a scrim tap closes the dialog only after Init() runs.
Expressive.Dialogs.i18n.confirm = 'Aceptar';
Expressive.Dialogs.i18n.cancel = 'Cancelar';
Methods
Call these on the <dialog> element. See
HTMLDialogElement
for the full API.
.showModal()
Opens the dialog as a modal. A basic dialog gets the scrim, and a full-screen dialog fills the page.
dialog.showModal();
.close()
Closes the dialog.
dialog.close();
A tap or click on the scrim also closes a basic dialog. Both ends
of the gesture have to land outside the dialog's box, so a drag
that starts on the dialog, such as selecting text or missing a
button, cannot dismiss it. Set closedby="none" or
closedby="closerequest" to opt out.
Tokens
Override these on the <dialog> to change the surface or width.
A basic dialog fades in and grows from 96% on springs, so motion="expressive"
applies to it. It closes at once. When the user requests reduced motion, it opens without
moving. Full-screen dialogs and sheets keep their own motion.
| Token | Default |
|---|---|
--md-comp-basic-dialog-container-color |
--md-sys-color-surface-container-high |
--md-comp-basic-dialog-container-shape |
28px |
--md-comp-basic-dialog-container-min-width |
280px |
--md-comp-basic-dialog-container-max-width |
560px |
--md-comp-basic-dialog-scrim-blur |
12px |
--md-comp-basic-dialog-easing, --md-comp-basic-dialog-duration |
The default spatial spring, which grows the dialog from 96% as it opens |
--md-comp-basic-dialog-effects-easing, --md-comp-basic-dialog-effects-duration |
The fast effects spring, used for the fade-in |
--md-comp-scrim-color |
--md-sys-color-scrim at 32% |