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
Thrown by Headless UI's internal focusIn() helper when the focus flag passed to it does not include any directional bit (Focus.First, Focus.Previous, Focus.Next, or Focus.Last). focusIn() computes a movement direction from these flags; without one, there is no direction to move and the API contract is violated. This almost always means a caller passed 0, an undefined value, or only modifier flags like Focus.NoScroll.
Source
Thrown at packages/@headlessui-react/src/utils/focus-management.ts:280
if (skipElements.length > 0 && elements.length > 1) {
elements = elements.filter(
(element) =>
!skipElements.some(
(skipElement) =>
skipElement != null && 'current' in skipElement
? skipElement?.current === element // Handle MutableRefObject
: skipElement === element // Handle HTMLElement directly
)
)
}
relativeTo = relativeTo ?? (root?.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 loopsView on GitHub (pinned to eea57cf46f)
Solutions
- Pass a directional flag: use focusIn(elements, Focus.First) or combine with modifiers, e.g. focusIn(elements, Focus.First | Focus.NoScroll).
- If the flag comes from a variable, verify it is always one of Focus.First/Previous/Next/Last (optionally OR-ed with Focus.NoScroll) and never 0/undefined.
- Check for duplicate @headlessui-react installs (npm ls @headlessui/react) and dedupe so enum values are consistent.
Example fix
// before focusIn(elements, Focus.NoScroll) // no direction bit -> throws // after focusIn(elements, Focus.First | Focus.NoScroll)
Defensive patterns
Strategy: validation
Validate before calling
import { Focus } from '@headlessui/react'
const DIRECTION = Focus.First | Focus.Previous | Focus.Next | Focus.Last
function isValidFocusFlag(focus: number): boolean {
return (focus & DIRECTION) !== 0
}
// before calling:
if (!isValidFocusFlag(flags)) flags = Focus.First
focusIn(elements, flags) Type guard
const hasDirection = (f: number): f is number => (f & (Focus.First | Focus.Previous | Focus.Next | Focus.Last)) !== 0
Try / catch
try { focusIn(elements, flags) } catch (e) { if (e instanceof Error && e.message.includes('Missing Focus.')) { focusIn(elements, Focus.First) } else throw e } Prevention
- Always type focus parameters as Focus (the enum), not number, so invalid masks are caught at compile time.
- Centralize flag construction in one helper that asserts a direction bit is present.
- Keep a single copy of @headlessui-react in the dependency tree to avoid enum drift.
When it happens
Trigger: Calling focusIn(elements, Focus.NoScroll) with no directional bit; passing 0 or an undefined `focus` argument; building a custom flag mask that omits First/Previous/Next/Last; internal components invoked with a corrupted Focus enum (e.g. tree-shaking or duplicate @headlessui versions mangling the enum values).
Common situations: Custom widgets copying Headless UI internals; passing a focus option read from user input/config that defaults to 0; mixing two different @headlessui-react versions in a monorepo so the Focus enum values from one copy don't match the other's.
Related errors
- Invalid role [${role}] passed to <Dialog />. Only `dialog` a
- There are no focusable elements inside the <FocusTrap />
- Invalid role [${role}] passed to <Dialog />. Only `dialog` a
- There are no focusable elements inside the <FocusTrap />
- Passing props on "Fragment"! The current component <${name}
AI-assisted analysis of tailwindlabs/headlessui@eea57cf46f (2026-08-28).
Data as JSON: /api/errors/17cc051b78b513ce.
Report an issue: GitHub.