Combobox
Filters large lists to selectable options based on the matching query.
Used inside a Modal
It is common to use Combobox inside a Modal. On mobile, the Modal automatically renders a Dialog instead.
Best Practices
When to use
- Pick
<Combobox>when users type to filter a known list of values (regions, frameworks, env-var names). - For short, fixed lists where typing adds nothing, switch to Select.
- When more than one value can be chosen at once, use MultiSelect.
- For free-form filter strings that don’t resolve to a single option, drop in Input with the
searchvariant.
Behavior
- Show a loading state for async results; don’t collapse the list while the request is in flight.
- Render a custom empty state of the form
No {items} match "{query}"rather than a bareNo results. - Inside a Modal, Geist switches to a Dialog on mobile automatically; don’t layer a second portal.
- Keep arrow-key navigation through
<Combobox.Option>items; don’t hijack Enter to submit the surrounding form while the list is open.
Content
- Visible label is a short Title Case noun (
Region,Environment Variable Name). - Placeholder is the inline hint:
Search regions,DATABASE_URL. Never bareSearch…and never the label restated. - Option text is Title Case for short values and matches canonical branding (
Next.js, notNextJS); same register across the list. - Validation names the field and constraint, sentence case with a period (
Select a region.).
Accessibility
<Combobox>has nolabelprop; pair a sibling<Label htmlFor>with the rootid, or setaria-labelon the root for icon-only triggers.- The root accepts
aria-labelonly; there is noaria-labelledbyprop, so the sibling-label path is the way to reference visible text. - Trap focus inside the popover when nested in a Modal so Tab cycles options instead of the page behind it.
Was this helpful?