Dialog

A modal <dialog> whose opening and closing are animated, while showModal(), the focus trap, Esc, returnValue and focus restore stay native.

Live example: two layouts

layout: 'behind'

The effect paints the panel's sheet behind its content: the dialog appears from nothing, through the ink. The veil behind is plain CSS.

Liquid glass

The backdrop is a pane of liquid glass drawn with WebGPU (liquidGlassEffect, GLSL where WebGPU is missing), over a page frosted by CSS. Its surface drifts to a stop and the still frame stays (keepBackdrop). WGSL effects need a renderer of their own.

Glass

The frosting is CSS (backdrop-filter): WebGL cannot read the page behind. The shader adds what CSS cannot while the glass forms, a rim with a faint RGB split and a sweep of light, and is transparent at the end.

Halftone

The backdrop is a screen of ink dots sized by noise, and the sheet appears from nothing, both in one shader. The noise keeps drifting after the opening, slows to a stop, and that still frame stays as the backdrop image (keepBackdrop).

layout: 'viewport'

The default: the effect paints the backdrop behind the panel, and the panel fades in with --p.

Usage

<dialog id="confirm" closedby="any" aria-labelledby="confirm-title">
  <div class="panel" data-fx-panel>
    <form method="dialog">
      <h2 id="confirm-title">Save changes?</h2>
      <button value="cancel">Cancel</button>
      <button value="ok">Save</button>
    </form>
  </div>
</dialog>
import { createRenderer, createDialogFx, inkVeilEffect } from 'webgl-ui'
import 'webgl-ui/src/elements/dialog/dialog.css' // the CSS contract

const renderer = createRenderer()
const dialog = document.querySelector<HTMLDialogElement>('#confirm')!

// Register your own `cancel` listeners BEFORE this line: whoever vetoes the close first wins.
createDialogFx(dialog, { renderer, effect: inkVeilEffect, layout: 'behind' })

dialog.showModal() // same signature as the native method, now animated

Options

OptionTypeDefaultDescription
rendererRenderer | () => RendererrequiredThe shared renderer.
effectEffectDefbackdropEffectWith 'viewport' or 'behind' a veil such as inkVeilEffect; with 'host' a cover such as inkEffect.
layout'viewport' | 'behind' | 'host''viewport'viewport: the effect is the backdrop. behind: the effect paints the panel's sheet behind its content, so the dialog appears from nothing. host: the effect covers the dialog box. With behind and host the backdrop is CSS.
durationnumber1200Opening in ms; closing takes 65%.
keepBackdropbooleanfalseviewport only: after the opening the effect keeps moving for drift ms, slowing to a stop; then its still frame becomes the ::backdrop image, for backdrops CSS cannot draw (noise, halftone). The canvas still goes away.
driftnumber3500With keepBackdrop: how long the backdrop keeps moving after the opening. Opening plus drift stay under five seconds by default (WCAG 2.2.2).
paintsPanelbooleanfalseviewport only: the effect also paints the panel's sheet (it gets uPanel and uSheet); the panel is transparent while animating.
trace(message) => voidnoneDebug hook.

Returns

MemberDescription
showModal()Native call, synchronous (same errors), then the animation. Also installed on the element.
close(returnValue?)Animated; the native close() runs at the end, with the close event and focus restore.
destroy()Restores the native methods and removes the listeners.
debug(){ open, target, running, progress }.

CSS contract

Import src/elements/dialog/dialog.css or copy it. It expects:

HookMeaning
[data-fx-panel]The visible surface, inside a transparent <dialog> box.
--fx-rgb, --fx-aBackdrop color and alpha, read by both CSS and shader, so the hand-over at the end is invisible.
[data-animating], --pSet on the dialog while animating.
[data-fx-host]Present with behind and host: the backdrop fades in with --p.
[data-fx-behind]Present with behind: the panel's background is transparent while animating, the shader paints it.
--fx-coverThe color the shader paints with behind and host (and uSheet with paintsPanel): set it to the panel's background.
[data-fx-snapshot], --fx-backdrop-imageWith keepBackdrop: the backdrop shows the still frame (redrawn if the window is resized). Removed when the dialog closes.
[data-fx-ambient]With keepBackdrop, while the backdrop drifts to a stop: the canvas still draws it, the ::backdrop is transparent.

Behavior and accessibility

Full table: native parity, dialog.