Dialog

A centered modal over a frosted backdrop that dims the page.

Basic

The .dialog root holds a .dialog__backdrop and a .dialog__panel wrapping the visible .dialog__content (header, body, footer, and a floating close chip). Open and close, focus trapping, scroll lock, and the static-backdrop shake come from the @stisla/vanilla layer: put data-stisla-dialog + an id on the root, point a data-stisla-dialog-trigger="id" button at it, and mark the backdrop and any close controls with data-stisla-dialog-dismiss. A header titles the dialog, the body carries the message, and the footer trails its actions. The close chip floats over the top-trailing corner. Add autofocus to any control inside the panel to land focus there on open. The demos below are live, each contained to its own frame.

Keyboard

Focus is trapped inside the dialog while it's open. On open, focus lands on the first element marked autofocus, falling back to .dialog__close; on close, focus returns to the trigger that opened it.

  • Tab: cycle focus forward through focusable controls (wraps to the first)
  • Shift + Tab: cycle focus backward (wraps to the last)
  • Escape: dismiss the dialog (unless the backdrop is static, see Static backdrop below)

Scrollable body

Add .dialog__panel--scrollable so a long body scrolls while the header and footer stay pinned. The panel height is bounded to the viewport.

Fullscreen

.dialog--fullscreen drops the outer margin and corner radius so the panel takes the whole viewport, for immersive flows.

Sizes

Width modifiers on the root swap the panel size: the default sits mid-scale, with .dialog--sm, .dialog--lg, .dialog--xl, and .dialog--almost-fullscreen (a breathing strip around an otherwise full-viewport panel).

Positioning

The panel centers by default. .dialog__panel--top drops it in from above and .dialog__panel--bottom anchors it to the lower edge.

Static backdrop

Set data-stisla-dialog-backdrop="static" (with data-stisla-dialog-keyboard="false" to also block ESC) for a deliberate dismiss: a backdrop click shakes the panel instead of closing. Explicit dismiss controls still close.

Confirmation

The alert-dialog pattern for a destructive action: role="alertdialog", a tinted.icon-box for tone, a centered heading and description, and a Cancel / confirm pair. A small width keeps it focused.

Success

A celebratory end-of-flow state: the icon on top, the heading and description in the middle, and a single block button to the next step.

Media hero

Drop the header when the leading row is media. The floating close still sits at the top-trailing corner and reads against the image.

Lightbox

Override the surface variables on a single dialog to turn it into a frame for media. The blurred backdrop and the floating close carry the affordance.

Events

Four events fire on the .dialog root. The opening and closing events are cancelable.

stisla:dialog:opening fires before the panel mounts and the backdrop fades in. Call preventDefault() to abort (useful for an external readiness check).

stisla:dialog:opened fires once the open transition lands and focus is in place.

stisla:dialog:closing fires before the close transition starts. Call preventDefault() to keep it open (useful for unsaved-changes guards).

stisla:dialog:closed fires once the panel is fully hidden and focus has returned to the trigger.

Customization

These variables retune the dialog. Override on the root or any wrapper.

VariableUse
--dialog-z-indexOverlay stacking order
--dialog-widthPanel width cap; the size modifiers retune this
--dialog-margin-block / -margin-inlineGap between the panel and the viewport edges
--dialog-bg / -color / -border-colorContent fill, text, and rim
--dialog-radius / -shadowContent corner radius and elevation
--dialog-padding-block / -padding-inlineHeader and body interior padding
--dialog-title-font-size / -title-font-weightTitle type
--dialog-footer-bg / -footer-border-color / -footer-padding-blockFooter seam fill, divider, and padding
--dialog-backdrop-bg / -backdrop-blurScrim color and blur radius
--dialog-close-size / -close-color / -close-bg / -close-bg-hoverClose chip size and frosted paint
--dialog-transition-durationFade and scale timing; zeroed under reduced-motion

Size modifiers set --dialog-width: .dialog--sm, .dialog--lg, .dialog--xl, plus .dialog--almost-fullscreen. Position the panel with .dialog__panel--top or .dialog__panel--bottom instead of the default center.