Primitives / foldkit-primitives/interaction

Overlay

namespace · packages/primitives/src/interaction/overlay.ts:19

export * as Overlay from './overlay.js'

One overlay policy value instead of nine subtly different overlay implementations. modal and nonModal cover the two shapes; anything else is an explicit Policy. behaviors turns a policy into the existing pieces — DismissLayer marking, FocusScope, ScrollLock, HideOutside — attached to one layer slot, with nothing reimplemented: the mounts are the shared implementation, and the data attributes are the stack's protocol. Positioning stays per-widget (Anchor.behavior directly): it binds a floating element to an external id, a different shape than this layer policy. Presence stays CSS (data-open): it needs a per-overlay placement, which is the Drawer's, not the policy's.

The DismissLayer stack bundle itself is placed once per app, not per overlay; its Dismiss outmessage reaches the app through the placement's onOut, which closes the dismissed layers. The id behaviors writes is the layer attribute (data-foldkit-plus-layer), not an element id: aria-controls has to name an element that exists.

In the guides

Members

Overlay.behaviors

function · packages/primitives/src/interaction/overlay.ts:72

function behaviors<Slots>(
  slots: Slots,
): <Input, ParentMessage, StackField extends string>(options: {
  readonly stack: Declared<typeof dismissLayerBundle, StackField>
  readonly layer: keyof Slots & string
  readonly trigger?: keyof Slots & string
  readonly id: (input: Input) => string
  readonly policy: Policy
}) => ReadonlyArray<NamedBehavior<Slots, Input, ParentMessage>>

The policy as behaviors, to spread into the view's pipe alongside the widget's own. Conditional pieces are included or left out when the list is built — a static policy per composition — so no slot carries a mount its policy never uses.

Overlay.DismissPolicy

interface · packages/primitives/src/interaction/overlay.ts:25

interface DismissPolicy {
  readonly outside: boolean
  readonly escape: boolean
}

Overlay.FocusPolicy

interface · packages/primitives/src/interaction/overlay.ts:32

interface FocusPolicy {
  readonly contain: boolean
  readonly restore: boolean
  readonly initialFocus?: string
}

const · packages/primitives/src/interaction/overlay.ts:51

const modal = { dismiss, focus, scroll, inert }

A modal overlay: dismissed by Escape and outside press, focused, locked, inert.

Overlay.nonModal

const · packages/primitives/src/interaction/overlay.ts:59

const nonModal = { dismiss, focus, scroll, inert }

A modeless overlay: dismissed by Escape and outside press, focus restored, page usable.

Overlay.Policy

interface · packages/primitives/src/interaction/overlay.ts:41

interface Policy {
  readonly dismiss: DismissPolicy
  readonly focus: FocusPolicy
  readonly scroll: {
    readonly lock: boolean
  }
  readonly inert: boolean
}