Skip to content

Dialog

Dialog opens a native modal panel, drawer, full-screen sheet or media view with a titled bar, a close button and a blurred backdrop.

01Preview

02Usage

Load @dg/ui/styles.css once in the root layout. Keep a reference with bind:this and open the dialog from a button.

<script>
  import { Button, Dialog } from "@dg/ui";
  /** @type {ReturnType<typeof Dialog>} */
  let dialog;
  let expanded = $state(false);
</script>

<Button
  label="Filters"
  aria-haspopup="dialog"
  aria-controls="filters"
  aria-expanded={expanded}
  onclick={(event) => {
    expanded = true;
    dialog.open(event);
  }}
/>
<Dialog bind:this={dialog} id="filters" title="Filters" placement="start" onclose={(event) => (expanded = event.currentTarget.open)}>
  <p>Choose the works to display.</p>
</Dialog>

The media placement shows an image or other media over the blurred page. Controls placed in the content, such as previous and next buttons, take absolute positions in the band kept free around it.

<script>
  import { Dialog } from "@dg/ui";
  let { images } = $props();
  let current = $state(0);
  /** @type {ReturnType<typeof Dialog>} */
  let dialog;

  /** @param {number} index @param {MouseEvent} event */
  function show(index, event) {
    current = index;
    dialog.open(event);
  }
</script>

{#each images as image, index (image.src)}
  <button type="button" onclick={(event) => show(index, event)}><img src={image.src} alt={image.alt} /></button>
{/each}
<Dialog
  bind:this={dialog}
  title="Gallery"
  placement="media"
  onkeydown={(event) => {
    if (event.key === "ArrowRight") current = (current + 1) % images.length;
  }}
>
  <img src={images[current].src} alt={images[current].alt} />
</Dialog>

03Notes

  • Native HTML attributes, DOM callbacks, class and style are forwarded to the dialog element. Use id with a trigger's aria-controls, and read event.currentTarget.open in onclose to follow the state: a dialog reopened right after closing can still receive the earlier close event.
  • Forwarding uses native attribute types; unknown props are not supported. Pass class as a string. Dialog owns open and its accessible name.
  • Panels and drawers scroll their content below a fixed bar. The full placement composes Page: pass framed sections as children, give the last one flex: 1 to carry the frame rails to the bottom, and let the page scroll.
  • While the dialog is open, the document does not scroll. The backdrop is translucent and blurred, except in the full placement, which covers the page.
  • The media placement is a transparent full-screen surface. Its title is visually hidden but still names the dialog, and the close button floats in a framed box at the top right. Content is centered and kept clear of a control-sized band on every side, reduced to a narrow inset at the inline edges below --narrow; size media with max-inline-size: 100% and max-block-size: 100%. A press beside the content, on the surface itself, closes the dialog.

04Parameters

NameTypeDefaultDescription
titlestringRequiredVisible title in the dialog bar, hidden in the media placement, and accessible name of the dialog.
placement'center' | 'start' | 'end' | 'full' | 'media'"center"Centered panel, full-height drawer from the inline start or end edge, opaque full-screen framed sheet, or transparent full-screen surface for media.
closeLabelstringundefinedAccessible name of the close button. Defaults to the built-in text in the Page language.
childrenSnippetundefinedDialog content. It renders only while the dialog is open, so its local state resets at each opening.

05Overrides

NameTypeDefaultDescription
--dialog-widthCSS length42rem (center), 26rem (start, end)Preferred width of the centered panel and drawers, still limited by the viewport. Set it through style; full and media placements ignore it.

06Methods

NameDescription
open()Show the modal. Pass the activating click event so pointer entry focuses the panel; keyboard entry focuses the first control.
close()Close the modal. Escape, the close button and a press on the backdrop also close it; focus returns to the previously focused element.

07Accessibility

Dialog uses the native modal dialog: content outside it is inert, Tab cycles inside it and Escape closes it. Its title names the dialog. Keyboard opening focuses the first control, normally the close button; pointer opening focuses the panel so the focus ring stays reserved for keyboard use. Closing returns focus to the trigger. When the content of a panel or drawer overflows, its scrolling body becomes a focusable region named by the title, so keyboard users can scroll long text that contains no controls; it draws its focus ring inside. The entry motion stops under reduced motion.

Related subjects

distributed·gallery