Skip to content
Alpha

Hololink UI is under active development. Components, APIs and these docs may change without notice.

Holo Dialog

The <holo-dialog> component wraps the native <dialog> element, using showModal()/close() for focus trapping, the top layer, and ::backdrop styling — no hand-rolled JS focus trap needed. When dismissible (the default), Esc, a backdrop click, or the close button dismiss the dialog. Closing returns focus to whatever element triggered it.

Use it for:

  • A task or message that needs the user’s full attention before they continue: confirm a deletion, edit a record.
  • Short, focused interactions with a clear way out.

Don’t use it for:

  • Non-blocking feedback. Use Toast or Alert.
  • Secondary panels that slide in from an edge. Use Drawer.
  • Lightweight floating content anchored to a trigger. Use Popover.
  • Long forms or whole pages. Give them their own page.

Are you sure you want to continue?

<button id="trigger">Open dialog</button>
<holo-dialog id="dialog" heading="Confirm action">
<p>Are you sure you want to continue?</p>
<button slot="footer">Confirm</button>
</holo-dialog>
<script>
trigger.addEventListener('click', () => dialog.setAttribute('open', ''));
dialog.addEventListener('holoClose', () => dialog.removeAttribute('open'));
</script>

The component renders a native <dialog> and opens it with showModal(). The browser makes the rest of the page inert, traps focus in the dialog and puts it in the top layer. It is named by its heading (an <h2> referenced with aria-labelledby), or by aria-label="Dialog" when no heading is set. The default slot is the body and the footer slot is the footer.

Key Action
Tab Moves to the next focusable element inside the dialog, wrapping at the end
Shift + Tab Moves to the previous focusable element, wrapping at the start
Esc Closes the dialog when dismissible
Enter, Space Activates the focused button (such as the close button)
  • When the dialog opens, the focused element is saved, following open shadow roots down to the element that really has focus (for example the inner <button> of a Button). Focus returns to it when the dialog closes.
  • With dismissible (the default) a close button named “Close dialog” is shown, and Esc and a backdrop click close the dialog.
  • With dismissible set to false there is no close button, and Esc and backdrop clicks are ignored. Close the dialog from your own content by setting open to false. Browsers may still close a modal dialog if Esc is pressed repeatedly without other interaction, so keep open in sync with holoClose.
  • Initial focus follows the browser default for showModal(): the first focusable element.
  • The fade only runs when prefers-reduced-motion: no-preference.

You provide:

  • A heading. Without it the dialog is named only “Dialog”.
  • At least one focusable control inside the dialog, and a clear way to finish or cancel. With dismissible set to false, that control is the only way out.
  • A trigger that is still in the page when the dialog closes, so focus can return to it.

Importing

import '@philbob-sideprojects/hololink-ui/holo-dialog';

Properties

PropertyAttributeTypeDefaultDescription
dismissibledismissiblebooleantrueIf true, renders a close button in the header and lets Esc and backdrop clicks close the dialog. If false, close it from your own content by setting open to false.
headingheadingstring—Optional heading rendered in the dialog header.
openopenbooleanfalseWhether the dialog is open. Setting this to true calls the native showModal(); setting it to false calls close().

Events

EventDetailDescription
holoClosevoidEmitted after the dialog has closed (via Esc, backdrop click, the close button, or open being set to false; Esc and backdrop click only when dismissible). Focus then returns to the element that was focused when the dialog opened.
holoOpenvoidEmitted after the dialog opens in response to open becoming true.

Slots

SlotDescription
(default)The dialog body content.
footerAction buttons rendered in the dialog footer.

CSS custom properties

PropertyDescription
--holo-dialog-backdrop-bgBackground of the backdrop behind the dialog.
--holo-dialog-bgBackground color of the dialog.
--holo-dialog-max-widthMaximum width of the dialog.
--holo-dialog-radiusCorner radius of the dialog.
--holo-dialog-shadowBox shadow of the dialog.
--holo-dialog-text-colorText color of the dialog.