Introduction
Components
- Accordion
- Action Sheet
- Alert
- Audio Player
- Audio Recorder
- Audio Waveform
- Avatar
- Badge
- BottomSheet
- Button
- Camera
- Camera Preview
- Card
- Carousel
- Checkbox
- Collapsible
- Color Picker
- Combobox
- Date Picker
- File Picker
- Gallery
- Hello Wave
- Icon
- Image
- Input
- Input OTP
- Link
- MediaPicker
- Mode Toggle
- Onboarding
- ParallaxScrollView
- Picker
- Popover
- Progress
- Radio
- ScrollView
- SearchBar
- Separator
- Share
- Sheet
- Skeleton
- Spinner
- Switch
- Table
- Tabs
- Text
- Toast
- Toggle
- Video
- View
Charts
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
ComboboxValue,
} from '@/components/ui/combobox';
import React, { useState } from 'react';
const frameworks = [
{ value: 'react', label: 'React' },
{ value: 'vue', label: 'Vue' },
{ value: 'angular', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
{ value: 'next', label: 'Next.js' },
{ value: 'nuxt', label: 'Nuxt.js' },
];
export function ComboboxDemo() {
const [value, setValue] = useState('');
return (
<Combobox value={value} onValueChange={setValue}>
<ComboboxTrigger>
<ComboboxValue placeholder='Select framework...' />
</ComboboxTrigger>
<ComboboxContent>
<ComboboxInput placeholder='Search frameworks...' />
<ComboboxList>
<ComboboxEmpty>No framework found.</ComboboxEmpty>
{frameworks.map((framework) => (
<ComboboxItem key={framework.value} value={framework.value}>
{framework.label}
</ComboboxItem>
))}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
Installation
pnpm dlx bna-ui add combobox
Usage
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxGroup,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
ComboboxValue,
} from '@/components/ui/combobox';
<Combobox value={value} onValueChange={setValue}>
<ComboboxTrigger>
<ComboboxValue placeholder='Select framework...' />
</ComboboxTrigger>
<ComboboxContent>
<ComboboxInput placeholder='Search frameworks...' />
<ComboboxList>
<ComboboxEmpty>No framework found.</ComboboxEmpty>
<ComboboxItem value='react'>React</ComboboxItem>
<ComboboxItem value='vue'>Vue</ComboboxItem>
<ComboboxItem value='angular'>Angular</ComboboxItem>
</ComboboxList>
</ComboboxContent>
</Combobox>
Examples
Default
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
ComboboxValue,
} from '@/components/ui/combobox';
import React, { useState } from 'react';
const frameworks = [
{ value: 'react', label: 'React' },
{ value: 'vue', label: 'Vue' },
{ value: 'angular', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
{ value: 'next', label: 'Next.js' },
{ value: 'nuxt', label: 'Nuxt.js' },
];
export function ComboboxDemo() {
const [value, setValue] = useState('');
return (
<Combobox value={value} onValueChange={setValue}>
<ComboboxTrigger>
<ComboboxValue placeholder='Select framework...' />
</ComboboxTrigger>
<ComboboxContent>
<ComboboxInput placeholder='Search frameworks...' />
<ComboboxList>
<ComboboxEmpty>No framework found.</ComboboxEmpty>
{frameworks.map((framework) => (
<ComboboxItem key={framework.value} value={framework.value}>
{framework.label}
</ComboboxItem>
))}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
With Groups
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxGroup,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
ComboboxValue,
} from '@/components/ui/combobox';
import React, { useState } from 'react';
export function ComboboxGroups() {
const [value, setValue] = useState('');
return (
<Combobox value={value} onValueChange={setValue}>
<ComboboxTrigger>
<ComboboxValue placeholder='Select technology...' />
</ComboboxTrigger>
<ComboboxContent>
<ComboboxInput placeholder='Search technologies...' />
<ComboboxList>
<ComboboxEmpty>No technology found.</ComboboxEmpty>
<ComboboxGroup heading='Frontend Frameworks'>
<ComboboxItem value='react'>React</ComboboxItem>
<ComboboxItem value='vue'>Vue</ComboboxItem>
<ComboboxItem value='angular'>Angular</ComboboxItem>
<ComboboxItem value='svelte'>Svelte</ComboboxItem>
</ComboboxGroup>
<ComboboxGroup heading='Backend Frameworks'>
<ComboboxItem value='express'>Express.js</ComboboxItem>
<ComboboxItem value='fastify'>Fastify</ComboboxItem>
<ComboboxItem value='nestjs'>NestJS</ComboboxItem>
<ComboboxItem value='koa'>Koa</ComboboxItem>
</ComboboxGroup>
<ComboboxGroup heading='Mobile'>
<ComboboxItem value='react-native'>React Native</ComboboxItem>
<ComboboxItem value='flutter'>Flutter</ComboboxItem>
<ComboboxItem value='ionic'>Ionic</ComboboxItem>
</ComboboxGroup>
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
Multiple Selection
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
ComboboxValue,
} from '@/components/ui/combobox';
import React, { useState } from 'react';
const skills = [
{ value: 'javascript', label: 'JavaScript' },
{ value: 'typescript', label: 'TypeScript' },
{ value: 'react', label: 'React' },
{ value: 'vue', label: 'Vue' },
{ value: 'angular', label: 'Angular' },
{ value: 'nodejs', label: 'Node.js' },
{ value: 'python', label: 'Python' },
{ value: 'java', label: 'Java' },
{ value: 'csharp', label: 'C#' },
{ value: 'go', label: 'Go' },
];
export function ComboboxMultiple() {
const [values, setValues] = useState<string[]>([]);
return (
<Combobox multiple values={values} onValuesChange={setValues}>
<ComboboxTrigger>
<ComboboxValue placeholder='Select skills...' />
</ComboboxTrigger>
<ComboboxContent>
<ComboboxInput placeholder='Search skills...' />
<ComboboxList>
<ComboboxEmpty>No skill found.</ComboboxEmpty>
{skills.map((skill) => (
<ComboboxItem key={skill.value} value={skill.value}>
{skill.label}
</ComboboxItem>
))}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
Disabled
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
ComboboxValue,
} from '@/components/ui/combobox';
import React, { useState } from 'react';
const frameworks = [
{ value: 'react', label: 'React' },
{ value: 'vue', label: 'Vue' },
{ value: 'angular', label: 'Angular' },
];
export function ComboboxDisabled() {
const [value, setValue] = useState('react');
return (
<Combobox value={value} onValueChange={setValue} disabled>
<ComboboxTrigger>
<ComboboxValue placeholder='Select framework...' />
</ComboboxTrigger>
<ComboboxContent>
<ComboboxInput placeholder='Search frameworks...' />
<ComboboxList>
<ComboboxEmpty>No framework found.</ComboboxEmpty>
{frameworks.map((framework) => (
<ComboboxItem key={framework.value} value={framework.value}>
{framework.label}
</ComboboxItem>
))}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
With Custom Search
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
ComboboxValue,
} from '@/components/ui/combobox';
import React, { useState } from 'react';
const countries = [
{
value: 'us',
label: 'United States',
searchValue: 'united states america usa',
},
{
value: 'uk',
label: 'United Kingdom',
searchValue: 'united kingdom england britain uk',
},
{ value: 'ca', label: 'Canada', searchValue: 'canada canadian' },
{
value: 'au',
label: 'Australia',
searchValue: 'australia australian aussie',
},
{ value: 'de', label: 'Germany', searchValue: 'germany german deutschland' },
{ value: 'fr', label: 'France', searchValue: 'france french français' },
{ value: 'jp', label: 'Japan', searchValue: 'japan japanese nihon' },
{ value: 'cn', label: 'China', searchValue: 'china chinese zhongguo' },
];
export function ComboboxSearch() {
const [value, setValue] = useState('');
return (
<Combobox value={value} onValueChange={setValue}>
<ComboboxTrigger>
<ComboboxValue placeholder='Select country...' />
</ComboboxTrigger>
<ComboboxContent>
<ComboboxInput placeholder='Search countries...' />
<ComboboxList>
<ComboboxEmpty>No country found.</ComboboxEmpty>
{countries.map((country) => (
<ComboboxItem
key={country.value}
value={country.value}
searchValue={country.searchValue}
>
{country.label}
</ComboboxItem>
))}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
Form Integration
import { Button } from '@/components/ui/button';
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
ComboboxValue,
} from '@/components/ui/combobox';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React, { useState } from 'react';
const roles = [
{ value: 'frontend', label: 'Frontend Developer' },
{ value: 'backend', label: 'Backend Developer' },
{ value: 'fullstack', label: 'Full Stack Developer' },
{ value: 'mobile', label: 'Mobile Developer' },
{ value: 'devops', label: 'DevOps Engineer' },
{ value: 'qa', label: 'QA Engineer' },
{ value: 'designer', label: 'UI/UX Designer' },
];
export function ComboboxForm() {
const [selectedRole, setSelectedRole] = useState('');
const [error, setError] = useState('');
const [submitted, setSubmitted] = useState(false);
const handleSubmit = () => {
if (!selectedRole) {
setError('Please select a role');
return;
}
setError('');
setSubmitted(true);
// Reset after 2 seconds
setTimeout(() => {
setSubmitted(false);
setSelectedRole('');
}, 2000);
};
return (
<View style={{ gap: 16 }}>
<View>
<Text style={{ marginBottom: 8, fontWeight: '600' }}>Job Role *</Text>
<Combobox
value={selectedRole}
onValueChange={(value) => {
setSelectedRole(value);
setError('');
}}
>
<ComboboxTrigger error={!!error}>
<ComboboxValue placeholder='Select your role...' />
</ComboboxTrigger>
<ComboboxContent>
<ComboboxInput placeholder='Search roles...' />
<ComboboxList>
<ComboboxEmpty>No role found.</ComboboxEmpty>
{roles.map((role) => (
<ComboboxItem key={role.value} value={role.value}>
{role.label}
</ComboboxItem>
))}
</ComboboxList>
</ComboboxContent>
</Combobox>
{error && (
<Text style={{ color: 'red', fontSize: 12, marginTop: 4 }}>
{error}
</Text>
)}
</View>
<Button onPress={handleSubmit} disabled={submitted}>
{submitted ? 'Submitted!' : 'Submit'}
</Button>
</View>
);
}
Large Dataset
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
ComboboxValue,
} from '@/components/ui/combobox';
import React, { useState } from 'react';
// Generate a large dataset
const generateLargeDataset = () => {
const categories = [
'Technology',
'Science',
'Arts',
'Sports',
'Business',
'Health',
];
const adjectives = [
'Amazing',
'Innovative',
'Creative',
'Dynamic',
'Efficient',
'Modern',
];
const nouns = [
'Solution',
'Platform',
'System',
'Framework',
'Tool',
'Service',
];
const items = [];
for (let i = 0; i < 200; i++) {
const category = categories[i % categories.length];
const adjective = adjectives[Math.floor(Math.random() * adjectives.length)];
const noun = nouns[Math.floor(Math.random() * nouns.length)];
items.push({
value: `item-${i}`,
label: `${adjective} ${category} ${noun} ${i + 1}`,
searchValue: `${category} ${adjective} ${noun}`,
});
}
return items;
};
const largeDataset = generateLargeDataset();
export function ComboboxLarge() {
const [value, setValue] = useState('');
return (
<Combobox value={value} onValueChange={setValue}>
<ComboboxTrigger>
<ComboboxValue placeholder='Search from 200+ items...' />
</ComboboxTrigger>
<ComboboxContent maxHeight={300}>
<ComboboxInput placeholder='Type to search...' />
<ComboboxList>
<ComboboxEmpty>No items found in dataset.</ComboboxEmpty>
{largeDataset.map((item) => (
<ComboboxItem
key={item.value}
value={item.value}
searchValue={item.searchValue}
>
{item.label}
</ComboboxItem>
))}
</ComboboxList>
</ComboboxContent>
</Combobox>
);
}
API Reference
Combobox
The root component that manages the state and context for all child components.
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | - | The combobox components. |
value | string | "" | The selected value (single selection). |
onValueChange | (value: string) => void | - | Callback when single value changes. |
values | string[] | [] | The selected values (multiple selection). |
onValuesChange | (values: string[]) => void | - | Callback when multiple values change. |
disabled | boolean | false | Whether the combobox is disabled. |
multiple | boolean | false | Whether multiple selection is enabled. |
ComboboxTrigger
The button that triggers the combobox dropdown.
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | - | The trigger content (usually ComboboxValue). |
style | ViewStyle | - | Additional styles for the trigger. |
error | boolean | false | Whether to show error styling. |
ComboboxValue
Displays the selected value or placeholder text.
Prop | Type | Default | Description |
---|---|---|---|
placeholder | string | "Select..." | Placeholder text when no value. |
style | TextStyle | - | Additional styles for the text. |
ComboboxContent
The modal container for the dropdown content.
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | - | The dropdown content. |
maxHeight | number | 400 | Maximum height of the dropdown. |
ComboboxInput
The search input field within the dropdown.
Prop | Type | Default | Description |
---|---|---|---|
placeholder | string | "Search..." | Placeholder text for the input. |
style | ViewStyle | - | Additional styles for the container. |
autoFocus | boolean | true | Whether to auto-focus the input. |
ComboboxList
Container for the list of options with filtering capability.
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | - | The list items and groups. |
style | ViewStyle | - | Additional styles for the list. |
ComboboxEmpty
Displays when no items match the search query.
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | - | The empty state content. |
style | ViewStyle | - | Additional styles for the container. |
ComboboxGroup
Groups related options with an optional heading.
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | - | The group items. |
heading | string | - | Optional heading for the group. |
ComboboxItem
Individual selectable option within the combobox.
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | - | The item content. |
value | string | - | The value of the item. |
onSelect | (value: string) => void | - | Callback when item is selected. |
disabled | boolean | false | Whether the item is disabled. |
searchValue | string | - | Custom value for search filtering. |
style | ViewStyle | - | Additional styles for the item. |
Accessibility
The Combobox component is built with accessibility in mind:
- Full keyboard navigation support
- Screen reader compatible with proper ARIA attributes
- Focus management between trigger and dropdown
- Escape key closes the dropdown
- Search functionality works with assistive technologies
- Proper color contrast for all states
- Supports dynamic text sizing
Keyboard Shortcuts
- Space/Enter: Open dropdown when trigger is focused
- Escape: Close dropdown
- Arrow Keys: Navigate through options
- Enter: Select highlighted option
- Tab: Move focus to next element
- Type: Search for matching options