
Mantine Combobox
- 2.1k installs
- 58 repo stars
- Updated February 19, 2026
- mantinedev/skills
Mantine Combobox primitives skill.
About
The mantine-combobox skill builds custom dropdown select autocomplete multiselect and tags UI using Mantine Combobox primitives. Core workflow creates useCombobox store renders Combobox Target Dropdown Options handles onOptionSubmit filtering and custom option rendering. Built-in Select Autocomplete TagsInput are Combobox-based. Use creating searchable dropdowns multi-select tags input customizing option render adding custom filtering or any useCombobox Combobox.Target Combobox.Option task in React Mantine apps. useCombobox store with open close hooks. Combobox Target Dropdown Options structure. Custom select autocomplete multiselect tags. onOptionSubmit and custom filtering. Foundation under Mantine Select components. Mantine Combobox primitives skill. User asks Mantine Combobox useCombobox.
- useCombobox store with open close hooks.
- Combobox Target Dropdown Options structure.
- Custom select autocomplete multiselect tags.
- onOptionSubmit and custom filtering.
- Foundation under Mantine Select components.
Mantine Combobox by the numbers
- 2,070 all-time installs (skills.sh)
- +133 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #235 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
mantine-combobox capabilities & compatibility
- Capabilities
- custom dropdowns · tags input
- Use cases
- frontend · ui design
npx skills add https://github.com/mantinedev/skills --skill mantine-comboboxAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2.1k |
|---|---|
| repo stars | ★ 58 |
| Security audit | 3 / 3 scanners passed |
| Last updated | February 19, 2026 |
| Repository | mantinedev/skills ↗ |
Custom Mantine searchable select?
Build custom Mantine Combobox select autocomplete multiselect and tags inputs with useCombobox primitives.
Who is it for?
React devs using Mantine UI.
Skip if: Non-React stacks.
When should I use this skill?
User asks Mantine Combobox useCombobox.
What you get
Combobox-based dropdown or tags input.
- useCombobox hook usage
- Combobox component TSX
- Styles API theming config
By the numbers
- Documents useCombobox loop option defaulting to true for keyboard boundary navigation
Files
Mantine Combobox Skill
Overview
Combobox provides low-level primitives for building any select-like UI. The built-in Select, Autocomplete, and TagsInput components are all built on top of it.
Core Workflow
1. Create the store
const combobox = useCombobox({
onDropdownClose: () => combobox.resetSelectedOption(),
onDropdownOpen: () => combobox.selectFirstOption(),
});2. Render structure
<Combobox store={combobox} onOptionSubmit={handleSubmit}>
<Combobox.Target>
<InputBase
component="button"
pointer
rightSection={<Combobox.Chevron />}
onClick={() => combobox.toggleDropdown()}
>
{value || <Input.Placeholder>Pick value</Input.Placeholder>}
</InputBase>
</Combobox.Target>
<Combobox.Dropdown>
<Combobox.Options>
{options.map((item) => (
<Combobox.Option value={item} key={item}>{item}</Combobox.Option>
))}
</Combobox.Options>
</Combobox.Dropdown>
</Combobox>3. Handle submit
const handleSubmit = (val: string) => {
setValue(val);
combobox.closeDropdown();
};Target Types
| Scenario | Use |
|---|---|
| Button trigger (no text input) | <Combobox.Target targetType="button"> |
| Input trigger | <Combobox.Target> (default) |
| Pills + separate input (multi-select) | <Combobox.DropdownTarget> + <Combobox.EventsTarget> |
References
- [`references/api.md`](references/api.md) — Full API:
useComboboxoptions and store, all sub-component props, CSS variables, Styles API selectors - [`references/patterns.md`](references/patterns.md) — Code examples: searchable select, multi-select with pills, groups, custom rendering, clear button, form integration
Combobox API Reference
Table of Contents
---
useCombobox hook
const combobox = useCombobox(options?: UseComboboxOptions);Options:
interface UseComboboxOptions {
defaultOpened?: boolean;
opened?: boolean;
onOpenedChange?: (opened: boolean) => void;
onDropdownClose?: (eventSource: 'keyboard' | 'mouse' | 'unknown') => void;
onDropdownOpen?: (eventSource: 'keyboard' | 'mouse' | 'unknown') => void;
loop?: boolean; // Default: true — keyboard nav wraps at boundaries
scrollBehavior?: ScrollBehavior; // Default: 'instant'
}Returned store:
interface ComboboxStore {
// Dropdown state
dropdownOpened: boolean;
openDropdown(eventSource?: 'keyboard' | 'mouse' | 'unknown'): void;
closeDropdown(eventSource?: 'keyboard' | 'mouse' | 'unknown'): void;
toggleDropdown(eventSource?: 'keyboard' | 'mouse' | 'unknown'): void;
// Option keyboard navigation
selectActiveOption(): string | null;
selectFirstOption(): string | null;
selectNextOption(): string | null;
selectPreviousOption(): string | null;
resetSelectedOption(): void;
clickSelectedOption(): void;
updateSelectedOptionIndex(
target?: 'active' | 'selected' | number,
options?: { scrollIntoView?: boolean }
): void;
// Programmatic focus
focusSearchInput(): void;
focusTarget(): void;
}---
Combobox (root)
<Combobox
store={combobox} // required — ComboboxStore from useCombobox()
onOptionSubmit={fn} // (value: string, optionProps) => void
size="sm" // MantineSize | string, default: 'sm'
dropdownPadding={4} // number, default: 4
resetSelectionOnOptionHover // boolean
readOnly // boolean — disables all interactions
// + all Popover props (position, offset, width, withinPortal, etc.)
/>---
Sub-components
Combobox.Target
<Combobox.Target
targetType="input" // 'button' | 'input', default: 'input'
withKeyboardNavigation // boolean, default: true
withAriaAttributes // boolean, default: true
withExpandedAttribute // boolean, default: false
autoComplete="off" // string
>
{/* single child — the trigger element */}
</Combobox.Target>Use targetType="button" when the trigger is a button (Space key toggles dropdown).
Combobox.DropdownTarget
Marks the element used for dropdown positioning when separate from the keyboard events target. Used together with Combobox.EventsTarget in multi-select/pills patterns.
Combobox.EventsTarget
Receives keyboard events for dropdown navigation. Used alongside Combobox.DropdownTarget when the typing input is nested inside the trigger (e.g. inside PillsInput).
Combobox.Dropdown
<Combobox.Dropdown hidden={false}>
{/* dropdown content */}
</Combobox.Dropdown>Use hidden to hide without unmounting (preserves scroll position).
Combobox.Options
<Combobox.Options labelledBy="some-label-id">
{/* Combobox.Option or Combobox.Group elements */}
</Combobox.Options>Combobox.Option
<Combobox.Option
value="react" // string | number, required
active={false} // visually marks as selected; used by selectActiveOption()
disabled={false}
>
React
</Combobox.Option>Combobox.Search
Built-in search input, wired to keyboard navigation. Renders sticky at top of dropdown.
<Combobox.Search
value={search}
onChange={(e) => setSearch(e.currentTarget.value)}
placeholder="Search..."
withAriaAttributes // boolean, default: true
withKeyboardNavigation // boolean, default: true
// + all Input props
/>Combobox.Empty
<Combobox.Empty>Nothing found</Combobox.Empty>Combobox.Group
<Combobox.Group label="Frontend">
<Combobox.Option value="react">React</Combobox.Option>
</Combobox.Group>Combobox.Header / Combobox.Footer
<Combobox.Header>Custom header</Combobox.Header>
<Combobox.Footer>Custom footer</Combobox.Footer>Combobox.Chevron
<Combobox.Chevron size="sm" error={error} color="blue" />Combobox.ClearButton
<Combobox.ClearButton onClear={() => setValue(null)} />Combobox.HiddenInput
<Combobox.HiddenInput
value={value} // string | number | (string | number)[] | null
valuesDivider="," // string, default: ','
name="myField"
form="myForm"
/>---
CSS variables & Styles API
CSS variables (set on root element)
| Variable | Description |
|---|---|
--combobox-option-fz | Option font size (driven by size prop) |
--combobox-option-padding | Option padding (driven by size prop) |
--combobox-padding | Dropdown padding (driven by dropdownPadding, default 4px) |
Styles API selectors
| Selector | Element |
|---|---|
dropdown | Dropdown container |
options | Options listbox |
option | Individual option |
search | Search input |
empty | Nothing found message |
header | Dropdown header |
footer | Dropdown footer |
group | Group container |
groupLabel | Group label text |
Combobox Implementation Patterns
Table of Contents
- Basic select (button trigger)
- Searchable select (input trigger)
- Multi-select with pills
- Options with groups
- Custom option rendering
- Clear button
- Form integration (hidden input)
- Nothing found message
---
Basic select (button trigger)
function CustomSelect({ data }: { data: string[] }) {
const [value, setValue] = useState<string | null>(null);
const combobox = useCombobox({
onDropdownClose: () => combobox.resetSelectedOption(),
});
const options = data.map((item) => (
<Combobox.Option value={item} key={item} active={item === value}>
{item}
</Combobox.Option>
));
return (
<Combobox
store={combobox}
onOptionSubmit={(val) => {
setValue(val);
combobox.closeDropdown();
}}
>
<Combobox.Target targetType="button">
<InputBase
component="button"
type="button"
pointer
rightSection={<Combobox.Chevron />}
rightSectionPointerEvents="none"
onClick={() => combobox.toggleDropdown()}
>
{value || <Input.Placeholder>Pick value</Input.Placeholder>}
</InputBase>
</Combobox.Target>
<Combobox.Dropdown>
<Combobox.Options>{options}</Combobox.Options>
</Combobox.Dropdown>
</Combobox>
);
}---
Searchable select (input trigger)
Input acts as both trigger and search field. Filter options based on the typed value.
function SearchableSelect({ data }: { data: string[] }) {
const [value, setValue] = useState<string | null>(null);
const [search, setSearch] = useState('');
const combobox = useCombobox({
onDropdownClose: () => combobox.resetSelectedOption(),
onDropdownOpen: () => combobox.selectFirstOption(),
});
const shouldFilterOptions = data.every((item) => item !== search);
const filtered = shouldFilterOptions
? data.filter((item) => item.toLowerCase().includes(search.toLowerCase().trim()))
: data;
const options = filtered.length > 0
? filtered.map((item) => (
<Combobox.Option value={item} key={item}>{item}</Combobox.Option>
))
: <Combobox.Empty>Nothing found</Combobox.Empty>;
return (
<Combobox
store={combobox}
onOptionSubmit={(val) => {
setValue(val);
setSearch(val);
combobox.closeDropdown();
}}
>
<Combobox.Target>
<InputBase
rightSection={<Combobox.Chevron />}
value={search}
onChange={(e) => {
combobox.openDropdown();
combobox.updateSelectedOptionIndex();
setSearch(e.currentTarget.value);
}}
onClick={() => combobox.openDropdown()}
onFocus={() => combobox.openDropdown()}
onBlur={() => {
combobox.closeDropdown();
setSearch(value || '');
}}
placeholder="Search value"
rightSectionPointerEvents="none"
/>
</Combobox.Target>
<Combobox.Dropdown>
<Combobox.Options>{options}</Combobox.Options>
</Combobox.Dropdown>
</Combobox>
);
}---
Multi-select with pills
Use Combobox.DropdownTarget for the outer container and Combobox.EventsTarget around the text input inside it.
function MultiSelect({ data }: { data: string[] }) {
const combobox = useCombobox({ onDropdownClose: () => combobox.resetSelectedOption() });
const [search, setSearch] = useState('');
const [value, setValue] = useState<string[]>([]);
const handleValueSelect = (val: string) =>
setValue((current) =>
current.includes(val) ? current.filter((v) => v !== val) : [...current, val]
);
const handleValueRemove = (val: string) =>
setValue((current) => current.filter((v) => v !== val));
const options = data
.filter((item) => item.toLowerCase().includes(search.trim().toLowerCase()))
.map((item) => (
<Combobox.Option value={item} key={item} active={value.includes(item)}>
<Group gap="sm">
{value.includes(item) ? <CheckIcon size={12} /> : null}
<span>{item}</span>
</Group>
</Combobox.Option>
));
const pills = value.map((item) => (
<Pill key={item} withRemoveButton onRemove={() => handleValueRemove(item)}>
{item}
</Pill>
));
return (
<Combobox store={combobox} onOptionSubmit={handleValueSelect}>
<Combobox.DropdownTarget>
<PillsInput onClick={() => combobox.openDropdown()}>
<Pill.Group>
{pills}
<Combobox.EventsTarget>
<PillsInput.Field
onFocus={() => combobox.openDropdown()}
onBlur={() => combobox.closeDropdown()}
value={search}
placeholder="Search values"
onChange={(e) => {
combobox.updateSelectedOptionIndex();
setSearch(e.currentTarget.value);
}}
onKeyDown={(e) => {
if (e.key === 'Backspace' && search.length === 0) {
e.preventDefault();
handleValueRemove(value[value.length - 1]);
}
}}
/>
</Combobox.EventsTarget>
</Pill.Group>
</PillsInput>
</Combobox.DropdownTarget>
<Combobox.Dropdown>
<Combobox.Options>
{options.length > 0 ? options : <Combobox.Empty>Nothing found</Combobox.Empty>}
</Combobox.Options>
</Combobox.Dropdown>
</Combobox>
);
}---
Options with groups
const groups = data.map((group) => (
<Combobox.Group label={group.group} key={group.group}>
{group.items.map((item) => (
<Combobox.Option value={item.value} key={item.value}>
{item.label}
</Combobox.Option>
))}
</Combobox.Group>
));
// Inside Combobox.Dropdown:
<Combobox.Options>{groups}</Combobox.Options>---
Custom option rendering
Render any content inside Combobox.Option:
const options = data.map((item) => (
<Combobox.Option value={item.value} key={item.value}>
<Group>
<Avatar src={item.avatar} size="sm" />
<div>
<Text size="sm">{item.label}</Text>
<Text size="xs" c="dimmed">{item.email}</Text>
</div>
</Group>
</Combobox.Option>
));---
Clear button
const rightSection = value ? (
<Combobox.ClearButton onClear={() => { setValue(null); setSearch(''); }} />
) : (
<Combobox.Chevron />
);
<InputBase
rightSection={rightSection}
rightSectionPointerEvents={value ? 'all' : 'none'}
/>---
Form integration (hidden input)
// Single value
<Combobox.HiddenInput value={value} name="framework" />
// Multiple values (joined by comma by default)
<Combobox.HiddenInput value={selectedValues} name="frameworks" valuesDivider="," />---
Nothing found message
<Combobox.Dropdown>
<Combobox.Options>
{filteredOptions.length > 0
? filteredOptions
: <Combobox.Empty>Nothing found for "{search}"</Combobox.Empty>}
</Combobox.Options>
</Combobox.Dropdown>Related skills
How it compares
Pick mantine-combobox for Mantine-specific Combobox composition; pick generic React autocomplete skills when the project does not use Mantine.
FAQ
First step?
Create useCombobox store with dropdown callbacks.
Structure?
Combobox Target InputBase Dropdown Options.
Built-ins relation?
Select Autocomplete TagsInput built on Combobox.
Is Mantine Combobox safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.