Skip to main content
On this pageFunctions

Dom

Functions

advanceFocus

functionsource
/**
 * Focuses the next or previous focusable element in the document relative to the element matching the given selector.
 * Fails with `ElementNotFound` if the selector does not match an `HTMLElement`.
 */
(
  selector: string,
  direction: FocusDirection
): Effect<void, ElementNotFound>

clickElement

functionsource
/**
 * Programmatically clicks an element matching the given selector.
 * Fails with `ElementNotFound` if the selector does not match an `HTMLElement`.
 */
(selector: string): Effect<void, ElementNotFound>

closeModal

functionsource
/**
 * Closes a dialog element using `.close()`.
 * Cleans up the keyboard handlers installed by `showModal` and restores focus to
 * the element that was focused before the dialog opened (the trigger, or the
 * dialog beneath it when closing a stacked dialog).
 * Fails with `ElementNotFound` if the selector does not match an `HTMLDialogElement`.
 */
(selector: string): Effect<void, ElementNotFound>

detectElementMovement

functionsource
/**
 * Detects if the element matching the given selector moves in the viewport.
 * Snapshots the element's position via `getBoundingClientRect` and watches for
 * changes using a `ResizeObserver` plus window `scroll` and `resize` listeners.
 * Resolves when movement is detected. Falls back to completing immediately if
 * the element is missing.
 * 
 * Cleanup runs automatically when the fiber is interrupted (e.g. by
 * `Effect.raceFirst`), removing the observer and event listeners via
 * `AbortSignal`.
 */
(selector: string): Effect<void>

focus

functionsource
/**
 * Focuses an element matching the given selector after the next render has
 * committed.
 * 
 * Use `Dom.focus` inside a Command for focus that's caused by a Message
 * dispatching: a dialog opening, an input becoming the active step in a
 * form, returning focus to a trigger button after a popover closes,
 * keyboard navigation across a stable layout. The Command fires from
 * `update`'s return; the focus runs after the next render commits, so the
 * element is in place by the time `.focus()` runs.
 * 
 * Do not use `OnMount` for focus. The cause of focus-on-open is the
 * Message, not the element appearing. Mount is for per-instance lifecycle
 * effects bound to a VNode existing where the live element handle is
 * needed (positioning, portaling, observer attachment, library setup).
 * 
 * Section headings, articles, and other non-natively-focusable elements
 * are common URL fragment targets, but `.focus()` is a no-op on them
 * without a `tabindex`. Pass `makeFocusable: true` to inject
 * `tabindex="-1"` on the target if it has none, making programmatic
 * focus actually land. Pass `preventScroll: true` to suppress the
 * browser's default scroll-on-focus, useful when the focus call follows
 * a deliberate scroll that should not be undone. The two options compose
 * with `scrollIntoViewAfterPaint` for URL-fragment-navigation
 * accessibility: scroll the section into view, then focus the same
 * selector so keyboard users start Tab navigation from the target.
 * 
 * Fails with `ElementNotFound` if the selector does not match an `HTMLElement`.
 */
(
  selector: string,
  options?: Readonly<{
    makeFocusable: boolean
    preventScroll: boolean
  }>
): Effect<void, ElementNotFound>

inertOthers

functionsource
/**
 * Marks all DOM elements outside the given selectors as `inert` and
 * `aria-hidden="true"`. Walks each allowed element up to `document.body`,
 * marking siblings that don't contain an allowed element. Uses reference
 * counting so nested calls are safe.
 */
(
  id: string,
  allowedSelectors: readonly Array<string>
): Effect<void>

restoreInert

functionsource
/**
 * Restores all elements previously marked inert by `inertOthers` for the
 * given ID. Safe to call without a preceding `inertOthers`. Acts as a no-op
 * in that case.
 */
(id: string): Effect<void>

scrollIntoView

functionsource
/**
 * Scrolls an element into view by selector. Resolves the selector after
 * `Render.afterCommit`. Defaults to `{ block: 'nearest' }`; pass a different
 * `block` for use cases like URL-fragment landing where `'start'` is right.
 * For a target the same Message just brought into the DOM,
 * `scrollIntoViewAfterPaint` is the right choice.
 * 
 * Fails with `ElementNotFound` if the selector does not match an `HTMLElement`.
 */
(
  selector: string,
  options?: Readonly<{
    block: ScrollLogicalPosition
  }>
): Effect<void, ElementNotFound>

scrollIntoViewAfterPaint

functionsource
/**
 * Like `scrollIntoView`, but waits for `Render.afterPaint` instead of
 * `Render.afterCommit` before resolving the selector.
 * 
 * Reach for this when the target was just brought into the DOM by the same
 * Message that dispatches the scroll, such as a routing flow landing at a
 * URL fragment. The two-frame wait gives the runtime time to commit the new
 * Model and the browser time to lay it out before the scroll runs. For a
 * target that's already on screen, `scrollIntoView` is the lighter choice.
 * 
 * Defaults to `{ block: 'nearest' }`; pass `{ block: 'start' }` for URL
 * fragment landings where the target should sit at the top of the viewport.
 * 
 * Fails with `ElementNotFound` if the selector does not match an `HTMLElement`.
 */
(
  selector: string,
  options?: Readonly<{
    block: ScrollLogicalPosition
  }>
): Effect<void, ElementNotFound>

showModal

functionsource
/**
 * Opens a dialog element using `show()` with high z-index, focus trapping,
 * and Escape key handling. Uses `show()` instead of `showModal()` so that
 * DevTools (and any other high-z-index overlay) remains interactive. The
 * Dialog component provides its own backdrop, scroll locking, and transitions.
 * Fails with `ElementNotFound` if the selector does not match an `HTMLDialogElement`.
 * 
 * Pass `focusSelector` to focus an element inside the dialog when it opens.
 * 
 * Records the element that had focus when the dialog opened so `closeModal`
 * can return focus there, the way `showModal()` would natively.
 */
(
  selector: string,
  options?: Readonly<{
    focusSelector: string
  }>
): Effect<void, ElementNotFound>

waitForAnimationSettled

functionsource
/**
 * Waits for all CSS animations on the element matching the selector to settle.
 * Covers both CSS transitions and CSS keyframe animations via the Web Animations
 * API. Falls back to completing immediately if the element is missing or has no
 * active animations.
 * 
 * Leave animations must be finite. `animation-iteration-count: infinite` will
 * keep the underlying `.finished` promise pending and hang the caller.
 */
(selector: string): Effect<void>

Types

FocusDirection

typesource
/** Direction for focus advancement: forward or backward in tab order. */
type FocusDirection = "Next" | "Previous"

Constants

lockScroll

constsource
/**
 * Locks page scroll by setting `overflow: hidden` on the document element.
 * Compensates for scrollbar width with padding to prevent layout shift.
 * On iOS Safari, intercepts `touchmove` events to prevent page scroll
 * while allowing scrolling within overflow containers.
 * Uses reference counting so nested locks are safe. The page only unlocks
 * when every lock has been released.
 */
const lockScroll: Effect.Effect<void>

unlockScroll

constsource
/**
 * Releases one scroll lock. When the last lock is released, restores the
 * original `overflow` and `padding-right` on the document element.
 * On iOS Safari, removes the `touchmove` listener.
 */
const unlockScroll: Effect.Effect<void>

Stay in the update loop.

New releases, patterns, and the occasional deep dive.


Built with Foldkit.

© 2026 Devin Jameson