Skip to content

Dialog functions

import {
enhanceDialog,
lightDismiss,
routeCloseRequests,
lockScrollWhileOpen,
closeAnimated,
showModal,
supportsClosedBy,
supportsTopLayerExit,
} from "surface-elements/dialog"

These work on any <dialog>, not only drawers. They feature-detect: where the browser already does the job, they do nothing.

Every function that attaches listeners returns a cleanup. Call it when the dialog leaves the page.

Applies lightDismiss, routeCloseRequests and, unless you opt out, lockScrollWhileOpen. Returns one cleanup for all of them.

function enhanceDialog(
dialog: HTMLDialogElement,
options?: { lockScroll?: boolean } // default: true
): () => void

Fallback for closedby="any" where the browser lacks it. Closes the dialog when a click both starts and ends on the backdrop, so selecting text inside and releasing outside does not close it.

It only acts while the dialog is modal and has closedby="any". close defaults to () => closeAnimated(dialog).

function lightDismiss(
dialog: HTMLDialogElement,
close?: () => unknown
): () => void

Where exit transitions out of the top layer are not native, sends these through closeAnimated so they animate:

  • Esc (cancel)
  • command="close" from an invoker
  • a submit from <form method="dialog"> or a button with formmethod="dialog"; the button’s value becomes returnValue
function routeCloseRequests(dialog: HTMLDialogElement): () => void

Closes the dialog after its exit transition and resolves when it is closed.

Where the browser transitions display and overlay natively this is dialog.close(). Elsewhere it sets data-closing, waits for the dialog’s animations (2 s at most) and then closes. If the dialog is reopened during the exit, it stays open.

function closeAnimated(
dialog: HTMLDialogElement,
returnValue?: string
): Promise<void>

Opens the dialog as a modal. Unlike dialog.showModal(), it cancels an exit animation in progress and does nothing if the dialog is already open.

function showModal(dialog: HTMLDialogElement): void

Holds a scroll lock for as long as the dialog is open as a modal. A non-modal dialog.show() does not lock.

function lockScrollWhileOpen(dialog: HTMLDialogElement): () => void
Function Returns true when
supportsClosedBy() The browser supports closedby on dialogs.
supportsTopLayerExit() The browser can transition a dialog out of the top layer (overlay and a display transition).