Skip to main content
On this pageFunctions

Ui/Menu

Functions

create

functionsource

init

functionsource
/** Creates an initial menu model from a config. Defaults to closed with no active item. */
(config: InitConfig): Menu.Model

Types

ActivatedItem

typesource
/** Sent when an item is highlighted via arrow keys or mouse hover. Includes activation trigger. */
type ActivatedItem = CallableTaggedStruct<"ActivatedItem", {
  activationTrigger: Literals<readonly ["Pointer", "Keyboard"]>
  index: Number
}>

ActivationTrigger

typesource
/** Schema for the activation trigger: whether the user interacted via mouse or keyboard. */
type ActivationTrigger = Literals<readonly ["Pointer", "Keyboard"]>

BlurredItems

typesource
/** Sent when the menu items container loses focus. */
type BlurredItems = CallableTaggedStruct<"BlurredItems", {}>

Closed

typesource
/** Sent when the menu closes via Escape key or backdrop click. */
type Closed = CallableTaggedStruct<"Closed", {}>

DeactivatedItem

typesource
/** Sent when the mouse leaves an enabled item. */
type DeactivatedItem = CallableTaggedStruct<"DeactivatedItem", {}>

GroupHeading

typesource
/** Configuration for a group heading rendered above a group of items. */
type GroupHeading = Readonly<{
  className: string
  content: Html
}>

IgnoredMouseClick

typesource
/** Sent when a mouse click on the button is ignored because pointer-down already handled the toggle. */
type IgnoredMouseClick = CallableTaggedStruct<"IgnoredMouseClick", {}>

InitConfig

typesource
/** Configuration for creating a menu model with `init`. `isAnimated` enables animation coordination (default `false`). `isModal` locks page scroll and inerts other elements when open (default `false`). */
type InitConfig = Readonly<{
  id: string
  isAnimated: boolean
  isModal: boolean
}>

ItemConfig

typesource
/** Configuration for an individual menu item's appearance. */
type ItemConfig = Readonly<{
  className: string
  content: Html
}>

MovedPointerOverItem

typesource
/** Sent when the pointer moves over a menu item, carrying screen coordinates for tracked-pointer comparison. */
type MovedPointerOverItem = CallableTaggedStruct<"MovedPointerOverItem", {
  index: Number
  screenX: Number
  screenY: Number
}>

Opened

typesource
/** Sent when the menu opens via button click or keyboard. Contains an optional initial active item index: None for pointer, Some for keyboard. */
type Opened = CallableTaggedStruct<"Opened", {
  maybeActiveItemIndex: Option<Number>
}>

OutMessage

typesource
/**
 * Generic over `Value extends string` so consumers using the typed
 *  `Ui.Menu.create<MyUnion>()` factory receive `value: MyUnion` in the
 *  `Selected` OutMessage. Defaults to `string`.
 */
type OutMessage = Selected<Value>

PressedPointerOnButton

typesource
/** Sent when the user presses a pointer device on the menu button. Records pointer type and toggles for mouse. */
type PressedPointerOnButton = CallableTaggedStruct<"PressedPointerOnButton", {
  button: Number
  pointerType: String
  screenX: Number
  screenY: Number
  timeStamp: Number
}>

ReleasedPointerOnItems

typesource
/** Sent when the user releases a pointer on the items container, enabling drag-to-select for mouse. */
type ReleasedPointerOnItems = CallableTaggedStruct<"ReleasedPointerOnItems", {
  screenX: Number
  screenY: Number
  timeStamp: Number
}>

RequestedItemClick

typesource
/** Sent when Enter or Space is pressed on the active item, triggering a programmatic click on the DOM element. */
type RequestedItemClick = CallableTaggedStruct<"RequestedItemClick", {
  index: Number
}>

Searched

typesource
/** Sent when a printable character is typed for typeahead search. */
type Searched = CallableTaggedStruct<"Searched", {
  key: String
  maybeTargetIndex: Option<Number>
}>

Selected

typesource
/** Sent to the parent when a menu item is selected. Carries both the selected value (from the `viewInputs.items` array supplied at view time) and its index. The menu has already closed when this fires; the parent does not need to dispatch `Ui.Menu.close`. */
type Selected = Readonly<{
  _tag: "Selected"
  index: number
  value: Value
}>

SuppressedSpaceScroll

typesource
/** Sent when a Space key-up is captured to prevent page scrolling. */
type SuppressedSpaceScroll = CallableTaggedStruct<"SuppressedSpaceScroll", {}>

ViewInputs

typesource
/**
 * Per-render view inputs passed to `view` via `h.submodel`'s `viewInputs` field.
 * 
 *  The Menu emits a `Selected({ value, index })` OutMessage on commit.
 *  The menu has already closed by the time this fires; consumers
 *  pattern-match it in their `GotMenuMessage` handler to react.
 */
type ViewInputs = Readonly<{
  anchor: AnchorConfig
  attributes: ReadonlyArray<ChildAttribute>
  backdropAttributes: ReadonlyArray<ChildAttribute>
  backdropClassName: string
  buttonAttributes: ReadonlyArray<ChildAttribute>
  buttonClassName: string
  buttonContent: Html
  className: string
  groupAttributes: ReadonlyArray<ChildAttribute>
  groupClassName: string
  groupToHeading: (groupKey: string) => GroupHeading | undefined
  isButtonDisabled: boolean
  isItemDisabled: (item: Item, index: number) => boolean
  itemGroupKey: (item: Item, index: number) => string
  items: ReadonlyArray<Item>
  itemsAttributes: ReadonlyArray<ChildAttribute>
  itemsClassName: string
  itemsScrollAttributes: ReadonlyArray<ChildAttribute>
  itemsScrollClassName: string
  itemToConfig: (item: Item, context: Readonly<{
    isActive: boolean
    isDisabled: boolean
  }>) => ItemConfig
  itemToSearchText: (item: Item, index: number) => string
  separatorAttributes: ReadonlyArray<ChildAttribute>
  separatorClassName: string
}>

Constants

AnchorMenu

constsource
/**
 * The anchor-positioning Mount this Menu renders on its panel. Exposed so
 *  Scene tests can call `Scene.Mount.resolve(AnchorMenu, CompletedAnchorMenu())`
 *  to acknowledge the mount produced by the rendered panel.
 */
const AnchorMenu: MountDefinitionWithArgs<"AnchorMenu", {
  anchor: Struct<{
    gap: optional<Number>
    offset: optional<Number>
    padding: optional<Number>
    placement: optional<Literals<readonly ["top", "right", "bottom", "left", "top-start", "top-end", "right-start", "right-end", "bottom-start", "bottom-end", "left-start", "left-end"]>>
    portal: optional<Boolean>
  }>
  buttonId: String
}, {
  _tag: "CompletedAnchorMenu"
}>

ClearedSearch

constsource
/** Sent after the search debounce period to clear the accumulated query. */
const ClearedSearch: CallableTaggedStruct<"ClearedSearch", {
  version: Number
}>

ClickItem

constsource
/** Programmatically clicks the active menu item's DOM element. */
const ClickItem: CommandDefinitionWithArgs<"ClickItem", {
  id: String
  index: Number
}, Effect<{
  _tag: "CompletedClickItem"
}, never, never>>

CompletedAnchorMenu

constsource
/** Sent when the menu items panel mounts and Floating UI has positioned it. Update no-ops; the side effect is the act of positioning, surfaced for DevTools observability. */
const CompletedAnchorMenu: CallableTaggedStruct<"CompletedAnchorMenu", {}>

CompletedClickItem

constsource
/** Sent when the programmatic click command completes. */
const CompletedClickItem: CallableTaggedStruct<"CompletedClickItem", {}>

CompletedFocusButton

constsource
/** Sent when the focus-button command completes after closing or selecting. */
const CompletedFocusButton: CallableTaggedStruct<"CompletedFocusButton", {}>

CompletedFocusItems

constsource
/** Sent when the focus-items command completes after opening the menu. */
const CompletedFocusItems: CallableTaggedStruct<"CompletedFocusItems", {}>

CompletedInertOthers

constsource
/** Sent when the inert-others command completes. */
const CompletedInertOthers: CallableTaggedStruct<"CompletedInertOthers", {}>

CompletedLockScroll

constsource
/** Sent when the scroll lock command completes. */
const CompletedLockScroll: CallableTaggedStruct<"CompletedLockScroll", {}>

CompletedPortalMenuBackdrop

constsource
/** Sent when the menu backdrop mounts and is portaled to the document body. Update no-ops; surfaces the portal side effect for DevTools. */
const CompletedPortalMenuBackdrop: CallableTaggedStruct<"CompletedPortalMenuBackdrop", {}>

CompletedRestoreInert

constsource
/** Sent when the restore-inert command completes. */
const CompletedRestoreInert: CallableTaggedStruct<"CompletedRestoreInert", {}>

CompletedScrollIntoView

constsource
/** Sent when the scroll-into-view command completes after keyboard activation. */
const CompletedScrollIntoView: CallableTaggedStruct<"CompletedScrollIntoView", {}>

CompletedUnlockScroll

constsource
/** Sent when the scroll unlock command completes. */
const CompletedUnlockScroll: CallableTaggedStruct<"CompletedUnlockScroll", {}>

DelayClearSearch

constsource
/** Waits for the typeahead search debounce period before clearing the query. */
const DelayClearSearch: CommandDefinitionWithArgs<"DelayClearSearch", {
  version: Number
}, Effect<{
  _tag: "ClearedSearch"
  version: number
}, never, never>>

DetectMovementOrAnimationEnd

constsource
/** Detects whether the menu button moved or the leave animation ended. Whichever comes first; both outcomes signal the Animation submodel that leave is complete. */
const DetectMovementOrAnimationEnd: CommandDefinitionWithArgs<"DetectMovementOrAnimationEnd", {
  id: String
}, Effect<{
  _tag: "GotAnimationMessage"
  message: {
    _tag: "Showed"
  } | {
    _tag: "Hid"
  } | {
    _tag: "AdvancedAnimationFrame"
  } | {
    _tag: "EndedAnimation"
  }
}, never, never>>

FocusButton

constsource
/** Moves focus back to the menu button after closing. */
const FocusButton: CommandDefinitionWithArgs<"FocusButton", {
  id: String
}, Effect<{
  _tag: "CompletedFocusButton"
}, never, never>>

FocusItems

constsource
/** Moves focus to the menu items container after opening. */
const FocusItems: CommandDefinitionWithArgs<"FocusItems", {
  id: String
}, Effect<{
  _tag: "CompletedFocusItems"
}, never, never>>

GotAnimationMessage

constsource
/** Wraps an Animation submodel message for delegation. */
const GotAnimationMessage: CallableTaggedStruct<"GotAnimationMessage", {
  message: Union<[CallableTaggedStruct<"Showed", {}>, CallableTaggedStruct<"Hid", {}>, CallableTaggedStruct<"AdvancedAnimationFrame", {}>, CallableTaggedStruct<"EndedAnimation", {}>]>
}>

InertOthers

constsource
/** Marks all elements outside the menu as inert for modal behavior. */
const InertOthers: CommandDefinitionWithArgs<"InertOthers", {
  id: String
}, Effect<{
  _tag: "CompletedInertOthers"
}, never, never>>

LockScroll

constsource
/** Prevents page scrolling while the menu is open. */
const LockScroll: CommandDefinitionNoArgs<"LockScroll", Effect<{
  _tag: "CompletedLockScroll"
}, never, never>>

Message

constsource
/** Union of all messages the menu component can produce. */
const Message: S.Union<[typeof Opened, typeof Closed, typeof BlurredItems, typeof ActivatedItem, typeof DeactivatedItem, typeof SelectedItem, typeof MovedPointerOverItem, typeof RequestedItemClick, typeof Searched, typeof ClearedSearch, typeof CompletedFocusItems, typeof CompletedFocusButton, typeof CompletedLockScroll, typeof CompletedUnlockScroll, typeof CompletedInertOthers, typeof CompletedRestoreInert, typeof CompletedScrollIntoView, typeof CompletedClickItem, typeof IgnoredMouseClick, typeof SuppressedSpaceScroll, typeof CompletedAnchorMenu, typeof CompletedPortalMenuBackdrop, typeof GotAnimationMessage, typeof PressedPointerOnButton, typeof ReleasedPointerOnItems]>

Model

constsource
/** Schema for the menu component's state, tracking open/closed status, active item, activation trigger, and typeahead search. */
const Model: Struct<{
  activationTrigger: Literals<readonly ["Pointer", "Keyboard"]>
  animation: Struct<{
    id: String
    isShowing: Boolean
    transitionState: Literals<readonly ["Idle", "EnterStart", "EnterAnimating", "LeaveStart", "LeaveAnimating"]>
  }>
  id: String
  isAnimated: Boolean
  isModal: Boolean
  isOpen: Boolean
  maybeActiveItemIndex: Option<Number>
  maybeLastButtonPointerType: Option<String>
  maybeLastPointerPosition: Option<Struct<{
    screenX: Number
    screenY: Number
  }>>
  maybePointerOrigin: Option<Struct<{
    screenX: Number
    screenY: Number
    timeStamp: Number
  }>>
  searchQuery: String
  searchVersion: Number
}>

OutMessage

constsource
/** Union of out-messages the menu component can produce. Surfaced as the third element of `update`'s return tuple and pattern-matched by the parent. */
const OutMessage: Union<readonly [
  CallableTaggedStruct<"Selected", {
    index: Number
    value: String
  }>
]>

PortalMenuBackdrop

constsource
/**
 * The backdrop-portaling Mount this Menu renders. Exposed so Scene tests can
 *  call `Scene.Mount.resolve(PortalMenuBackdrop, CompletedPortalMenuBackdrop())` to
 *  acknowledge the mount produced by the rendered backdrop.
 */
const PortalMenuBackdrop: MountDefinitionNoArgs<"PortalMenuBackdrop", {
  _tag: "CompletedPortalMenuBackdrop"
}>

RestoreInert

constsource
/** Removes the inert attribute from elements outside the menu. */
const RestoreInert: CommandDefinitionWithArgs<"RestoreInert", {
  id: String
}, Effect<{
  _tag: "CompletedRestoreInert"
}, never, never>>

ScrollIntoView

constsource
/** Scrolls the active menu item into view after keyboard navigation. */
const ScrollIntoView: CommandDefinitionWithArgs<"ScrollIntoView", {
  id: String
  index: Number
}, Effect<{
  _tag: "CompletedScrollIntoView"
}, never, never>>

Selected

constsource
/** Sent to the parent when a menu item is selected. Carries both the selected value (from the `viewInputs.items` array supplied at view time) and its index. The menu has already closed when this fires; the parent does not need to dispatch `Ui.Menu.close`. */
const Selected: CallableTaggedStruct<"Selected", {
  index: Number
  value: String
}>

SelectedItem

constsource
/** Sent when an item is selected via Enter, Space, or click. */
const SelectedItem: CallableTaggedStruct<"SelectedItem", {
  index: Number
  item: String
}>

UnlockScroll

constsource
/** Re-enables page scrolling after the menu closes. */
const UnlockScroll: CommandDefinitionNoArgs<"UnlockScroll", Effect<{
  _tag: "CompletedUnlockScroll"
}, never, never>>

Stay in the update loop.

New releases, patterns, and the occasional deep dive.


Built with Foldkit.

© 2026 Devin Jameson