tailwindlabs/headlessui · error · Error
Missing `options` in virtual mode
Error message
Missing `options` in virtual mode
What it means
In Headless UI React's Combobox, virtual mode is enabled by passing `virtual={...}` (a virtualizer config). A useMemo then requires the top-level `options` prop to be present so it can feed the option list to the virtualizer; if `options === undefined` while `data.virtual` is set, it throws 'Missing `options` in virtual mode'.
Source
Thrown at packages/@headlessui-react/src/components/combobox/combobox.tsx:1355
//
// When the `static` prop is used, we should never freeze, because rendering
// is up to the user.
let shouldFreeze = visible && comboboxState === ComboboxState.Closed && !props.static
let options = useFrozenData(shouldFreeze, data.virtual?.options)
// Frozen state, the selected value will only update visually when the user re-opens the <Combobox />
let frozenValue = useFrozenData(shouldFreeze, data.value)
let isSelected = useCallback(
(compareValue: unknown) => data.compare(frozenValue, compareValue),
[data.compare, frozenValue]
)
// Map the children in a scrollable container when virtualization is enabled
let newDataContextValue = useMemo(() => {
if (!data.virtual) return data
if (options === undefined) throw new Error('Missing `options` in virtual mode')
return options !== data.virtual.options
? { ...data, virtual: { ...data.virtual, options } }
: data
}, [data, options, data.virtual?.options])
if (data.virtual) {
Object.assign(theirProps, {
children: (
<ComboboxDataContext.Provider value={newDataContextValue}>
{/* @ts-expect-error The `children` prop now is a callback function that receives `{option}` */}
<VirtualProvider slot={slot}>{theirProps.children}</VirtualProvider>
</ComboboxDataContext.Provider>
),
})
}
let render = useRender()View on GitHub (pinned to eea57cf46f)
Solutions
- Pass the flat options array as a prop: `<Combobox virtual={virtualizer} options={options}>`.
- If options load asynchronously, pass `options={options ?? []}` until loaded (or defer rendering the Combobox until data exists).
- Remember virtual mode requires options as data, not as <ComboboxOption> children.
Example fix
// before
<Combobox virtual={virtualizer} value={value} onChange={setValue}>
{options.map(o => <ComboboxOption key={o.id} value={o}>...</ComboboxOption>)}
</Combobox>
// after
<Combobox virtual={virtualizer} options={options} value={value} onChange={setValue}>
{opt => <div>{opt.label}</div>}
</Combobox> Defensive patterns
Strategy: validation
Validate before calling
<Combobox virtual={virtualizer} options={options ?? []} ... > Type guard
const hasOptions = (p: { options?: unknown[] }): boolean => p.options !== undefined Prevention
- In virtual mode always pass the options prop.
- Use `options ?? []` for async data.
- Don't rely on <ComboboxOption> children in virtual mode.
When it happens
Trigger: `<Combobox virtual={virtualizer}>` without an `options` prop; passing options only via `<ComboboxOption>` children (which don't work in virtual mode); destructuring options conditionally so it becomes undefined on some renders.
Common situations: Migrating a Combobox to @tanstack/react-virtual-based virtual mode and forgetting the required `options` array; supplying options to the virtualizer object but not as the `options` prop; lazy-loading options where the first render passes undefined.
Related errors
- You have to provide an `open` and an `onClose` prop to the `
- You provided an `onClose` prop to the `Dialog`, but forgot a
- You provided an `open` prop to the `Dialog`, but forgot an `
- Passing props on "Fragment"! The current component <${name}
- You provided an `open` prop to the `Dialog`, but the value i
AI-assisted analysis of tailwindlabs/headlessui@eea57cf46f (2026-08-28).
Data as JSON: /api/errors/1dbc0f40eca06e50.
Report an issue: GitHub.