tailwindlabs/headlessui · error · Error

Missing Focus.First, Focus.Previous, Focus.Next or Focus.Las

Error message

Missing Focus.First, Focus.Previous, Focus.Next or Focus.Last

What it means

`focusIn(container, focus)` from Headless UI's focus-management utility computes a traversal direction from the `focus` bitmask. It requires one of the directional flags Focus.First, Focus.Previous, Focus.Next, or Focus.Last; if none is set, the direction computation throws immediately.

Source

Thrown at packages/@headlessui-vue/src/utils/focus-management.ts:222

      : container?.ownerDocument) ?? document

  let elements = Array.isArray(container)
    ? sorted
      ? sortByDomNode(container)
      : container
    : getFocusableElements(container)

  if (skipElements.length > 0 && elements.length > 1) {
    elements = elements.filter((x) => !skipElements.includes(x))
  }

  relativeTo = relativeTo ?? (ownerDocument.activeElement as HTMLElement)

  let direction = (() => {
    if (focus & (Focus.First | Focus.Next)) return Direction.Next
    if (focus & (Focus.Previous | Focus.Last)) return Direction.Previous

    throw new Error('Missing Focus.First, Focus.Previous, Focus.Next or Focus.Last')
  })()

  let startIndex = (() => {
    if (focus & Focus.First) return 0
    if (focus & Focus.Previous) return Math.max(0, elements.indexOf(relativeTo)) - 1
    if (focus & Focus.Next) return Math.max(0, elements.indexOf(relativeTo)) + 1
    if (focus & Focus.Last) return elements.length - 1

    throw new Error('Missing Focus.First, Focus.Previous, Focus.Next or Focus.Last')
  })()

  let focusOptions = focus & Focus.NoScroll ? { preventScroll: true } : {}

  let offset = 0
  let total = elements.length
  let next = undefined
  do {
    // Guard against infinite loops

View on GitHub (pinned to eea57cf46f)

Solutions

  1. Include exactly one direction flag: `focusIn(container, Focus.First | Focus.NoScroll)`.
  2. If computing flags dynamically, assert a direction bit is present before calling: `(flags & (Focus.First|Focus.Previous|Focus.Next|Focus.Last)) !== 0`.
  3. Prefer using the library's built-in components/keyboard handling rather than calling focusIn directly.

Example fix

// before
focusIn(container, Focus.NoScroll)

// after
focusIn(container, Focus.First | Focus.NoScroll)
Defensive patterns

Strategy: validation

Validate before calling

const DIRECTION = Focus.First | Focus.Previous | Focus.Next | Focus.Last
if ((flags & DIRECTION) === 0) flags |= Focus.First
focusIn(container, flags)

Type guard

const hasDirection = (f: number) => (f & (Focus.First | Focus.Previous | Focus.Next | Focus.Last)) !== 0

Prevention

When it happens

Trigger: Calling `focusIn(el, Focus.NoScroll)` or `focusIn(el, 0)` (only modifier flags set); passing a custom numeric value that doesn't include a direction bit; building the flags dynamically and accidentally passing only Focus.WrapAround/NoScroll.

Common situations: Custom keyboard handlers in menus/dialogs that pass only modifier flags; refactor typos where the direction constant is dropped; calling the internal `focusIn`/`focusFrom` API directly instead of higher-level components.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of tailwindlabs/headlessui@eea57cf46f (2026-08-28). Data as JSON: /api/errors/129755f3406c5548. Report an issue: GitHub.