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 { Picker } from '@/components/ui/picker';
import React, { useState } from 'react';
export function PickerDemo() {
const [value, setValue] = useState<string>('');
const options = [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
{ label: 'Orange', value: 'orange' },
{ label: 'Grape', value: 'grape' },
];
return (
<Picker
options={options}
value={value}
onValueChange={setValue}
placeholder='Select a fruit...'
/>
);
}
Installation
pnpm dlx bna-ui add picker
Usage
import { Picker } from '@/components/ui/picker';
<Picker
options={[
{ label: 'Option 1', value: '1' },
{ label: 'Option 2', value: '2' },
{ label: 'Option 3', value: '3' },
]}
value={selectedValue}
onValueChange={setSelectedValue}
placeholder='Select an option...'
/>
Examples
Default
import { Picker } from '@/components/ui/picker';
import React, { useState } from 'react';
export function PickerDemo() {
const [value, setValue] = useState<string>('');
const options = [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
{ label: 'Orange', value: 'orange' },
{ label: 'Grape', value: 'grape' },
];
return (
<Picker
options={options}
value={value}
onValueChange={setValue}
placeholder='Select a fruit...'
/>
);
}
With Sections
import { Picker } from '@/components/ui/picker';
import React, { useState } from 'react';
export function PickerSections() {
const [value, setValue] = useState<string>('');
const sections = [
{
title: 'Fruits',
options: [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
{ label: 'Orange', value: 'orange' },
],
},
{
title: 'Vegetables',
options: [
{ label: 'Carrot', value: 'carrot' },
{ label: 'Broccoli', value: 'broccoli' },
{ label: 'Spinach', value: 'spinach' },
],
},
];
return (
<Picker
sections={sections}
value={value}
onValueChange={setValue}
placeholder='Select an item...'
modalTitle='Choose Food'
/>
);
}
Multiple Selection
import { Picker } from '@/components/ui/picker';
import React, { useState } from 'react';
export function PickerMultiple() {
const [values, setValues] = useState<string[]>([]);
const options = [
{ label: 'JavaScript', value: 'js' },
{ label: 'TypeScript', value: 'ts' },
{ label: 'Python', value: 'py' },
{ label: 'Java', value: 'java' },
{ label: 'C++', value: 'cpp' },
{ label: 'Rust', value: 'rust' },
];
return (
<Picker
options={options}
values={values}
onValuesChange={setValues}
placeholder='Select languages...'
multiple
modalTitle='Programming Languages'
/>
);
}
Searchable
import { Picker } from '@/components/ui/picker';
import React, { useState } from 'react';
export function PickerSearchable() {
const [value, setValue] = useState<string>('');
const options = [
{ label: 'United States', value: 'us' },
{ label: 'Canada', value: 'ca' },
{ label: 'United Kingdom', value: 'uk' },
{ label: 'Germany', value: 'de' },
{ label: 'France', value: 'fr' },
{ label: 'Japan', value: 'jp' },
{ label: 'Australia', value: 'au' },
{ label: 'Brazil', value: 'br' },
{ label: 'India', value: 'in' },
{ label: 'China', value: 'cn' },
];
return (
<Picker
options={options}
value={value}
onValueChange={setValue}
placeholder='Select a country...'
searchable
searchPlaceholder='Search countries...'
modalTitle='Countries'
/>
);
}
With Icons and Labels
import { Picker } from '@/components/ui/picker';
import { MapPin, Settings, User } from 'lucide-react-native';
import React, { useState } from 'react';
export function PickerStyled() {
const [location, setLocation] = useState<string>('');
const [user, setUser] = useState<string>('');
const [setting, setSetting] = useState<string>('');
const locations = [
{ label: 'New York', value: 'ny' },
{ label: 'Los Angeles', value: 'la' },
{ label: 'Chicago', value: 'chi' },
];
const users = [
{ label: 'John Doe', value: 'john' },
{ label: 'Jane Smith', value: 'jane' },
{ label: 'Bob Johnson', value: 'bob' },
];
const settings = [
{ label: 'Notifications', value: 'notifications' },
{ label: 'Privacy', value: 'privacy' },
{ label: 'Account', value: 'account' },
];
return (
<>
<Picker
options={locations}
value={location}
onValueChange={setLocation}
placeholder='Select location...'
icon={MapPin}
label='Location'
variant='outline'
/>
<Picker
options={users}
value={user}
onValueChange={setUser}
placeholder='Select user...'
icon={User}
label='User'
variant='filled'
style={{ marginTop: 16 }}
/>
<Picker
options={settings}
value={setting}
onValueChange={setSetting}
placeholder='Select setting...'
icon={Settings}
label='Settings'
variant='group'
style={{ marginTop: 16 }}
/>
</>
);
}
Variants
import { Picker } from '@/components/ui/picker';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React, { useState } from 'react';
export function PickerVariants() {
const [outlineValue, setOutlineValue] = useState<string>('');
const [filledValue, setFilledValue] = useState<string>('');
const [groupValue, setGroupValue] = useState<string>('');
const options = [
{ label: 'Small', value: 'sm' },
{ label: 'Medium', value: 'md' },
{ label: 'Large', value: 'lg' },
{ label: 'Extra Large', value: 'xl' },
];
return (
<View style={{ gap: 20 }}>
<View>
<Text variant='caption' style={{ marginBottom: 8 }}>
Outline Variant
</Text>
<Picker
options={options}
value={outlineValue}
onValueChange={setOutlineValue}
placeholder='Select size...'
variant='outline'
/>
</View>
<View>
<Text variant='caption' style={{ marginBottom: 8 }}>
Filled Variant
</Text>
<Picker
options={options}
value={filledValue}
onValueChange={setFilledValue}
placeholder='Select size...'
variant='filled'
/>
</View>
<View>
<Text variant='caption' style={{ marginBottom: 8 }}>
Group Variant
</Text>
<Picker
options={options}
value={groupValue}
onValueChange={setGroupValue}
placeholder='Select size...'
variant='group'
/>
</View>
</View>
);
}
Form Integration
import { Button } from '@/components/ui/button';
import { Picker } from '@/components/ui/picker';
import { View } from '@/components/ui/view';
import React, { useState } from 'react';
export function PickerForm() {
const [category, setCategory] = useState<string>('');
const [priority, setPriority] = useState<string>('');
const [errors, setErrors] = useState<{
category?: string;
priority?: string;
}>({});
const categories = [
{ label: 'Bug Report', value: 'bug' },
{ label: 'Feature Request', value: 'feature' },
{ label: 'General Inquiry', value: 'general' },
];
const priorities = [
{ label: 'Low', value: 'low' },
{ label: 'Medium', value: 'medium' },
{ label: 'High', value: 'high' },
{ label: 'Critical', value: 'critical' },
];
const handleSubmit = () => {
const newErrors: { category?: string; priority?: string } = {};
if (!category) {
newErrors.category = 'Please select a category';
}
if (!priority) {
newErrors.priority = 'Please select a priority';
}
setErrors(newErrors);
if (Object.keys(newErrors).length === 0) {
// Form is valid
console.log('Form submitted:', { category, priority });
}
};
return (
<View style={{ gap: 16 }}>
<Picker
options={categories}
value={category}
onValueChange={(value) => {
setCategory(value);
if (errors.category) {
setErrors((prev) => ({ ...prev, category: undefined }));
}
}}
placeholder='Select category...'
label='Category'
error={errors.category}
variant='outline'
/>
<Picker
options={priorities}
value={priority}
onValueChange={(value) => {
setPriority(value);
if (errors.priority) {
setErrors((prev) => ({ ...prev, priority: undefined }));
}
}}
placeholder='Select priority...'
label='Priority'
error={errors.priority}
variant='outline'
/>
<Button onPress={handleSubmit}>Submit Ticket</Button>
</View>
);
}
Advanced Features
import { Picker } from '@/components/ui/picker';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React, { useState } from 'react';
export function PickerAdvanced() {
const [plan, setPlan] = useState<string>('');
const sections = [
{
title: 'Individual Plans',
options: [
{
label: 'Basic',
value: 'basic',
description: '$9/month - Perfect for individuals',
},
{
label: 'Pro',
value: 'pro',
description: '$19/month - Advanced features included',
},
],
},
{
title: 'Team Plans',
options: [
{
label: 'Team',
value: 'team',
description: '$39/month - Collaboration tools',
},
{
label: 'Enterprise',
value: 'enterprise',
description: '$99/month - Full enterprise features',
},
{
label: 'Custom',
value: 'custom',
description: 'Contact us for pricing',
disabled: true,
},
],
},
];
return (
<View style={{ gap: 16 }}>
<Picker
sections={sections}
value={plan}
onValueChange={setPlan}
placeholder='Select a plan...'
modalTitle='Subscription Plans'
searchable
searchPlaceholder='Search plans...'
variant='outline'
/>
{plan && (
<View
style={{
padding: 12,
backgroundColor: '#f0f9ff',
borderRadius: 8,
borderWidth: 1,
borderColor: '#0284c7',
}}
>
<Text style={{ color: '#0284c7', fontWeight: '500' }}>
Selected:{' '}
{
sections.flatMap((s) => s.options).find((o) => o.value === plan)
?.label
}
</Text>
</View>
)}
</View>
);
}
API Reference
Picker
The main picker component that displays options in a modal.
Prop | Type | Default | Description |
---|---|---|---|
options | PickerOption[] | [] | Array of options to display. |
sections | PickerSection[] | [] | Array of sections containing grouped options. |
value | string | - | Currently selected value (single selection). |
values | string[] | [] | Currently selected values (multiple selection). |
placeholder | string | "Select an option..." | Placeholder text when no option is selected. |
error | string | - | Error message to display. |
variant | "outline" | "filled" | "group" | "filled" | Visual variant of the picker. |
onValueChange | (value: string) => void | - | Callback when single selection changes. |
onValuesChange | (values: string[]) => void | - | Callback when multiple selection changes. |
disabled | boolean | false | Whether the picker is disabled. |
multiple | boolean | false | Enable multiple selection mode. |
label | string | - | Label text to display. |
icon | React.ComponentType<LucideProps> | - | Icon component to display. |
rightComponent | ReactNode | (() => ReactNode) | - | Custom component to display on the right side. |
modalTitle | string | - | Title for the modal header. |
searchable | boolean | false | Enable search functionality. |
searchPlaceholder | string | "Search options..." | Placeholder for search input. |
style | ViewStyle | - | Additional styles for the picker container. |
inputStyle | TextStyle | - | Additional styles for the input text. |
labelStyle | TextStyle | - | Additional styles for the label text. |
errorStyle | TextStyle | - | Additional styles for the error text. |
PickerOption
Interface for individual picker options.
Property | Type | Default | Description |
---|---|---|---|
label | string | - | Display text for the option. |
value | string | - | Unique value for the option. |
description | string | - | Optional description text. |
disabled | boolean | - | Whether the option is disabled. |
PickerSection
Interface for grouping options into sections.
Property | Type | Default | Description |
---|---|---|---|
title | string | - | Optional section title. |
options | PickerOption[] | - | Array of options in section. |
Accessibility
The Picker component is built with accessibility in mind:
- Uses Modal component for proper focus management
- Supports keyboard navigation within the modal
- Provides proper touch targets for mobile devices
- Uses semantic color contrast for text and backgrounds
- Supports screen reader announcements