Select
The Select component allows users to choose one or more options from a list. It supports static and dynamic items, sections, various styling options, and accessibility features.
Installation
$ cbui-cli install @crossbuildui/select
cbui-cli
globally and authenticated your account. This will ensure you can access all the necessary features.Import
1import { Select, SelectItem, SelectSection } from '@/crossbuildui/select';
2// import Icon from 'react-native-vector-icons/MaterialIcons'; // Or your preferred icon library
Select Component
Basic Usage
Define options using SelectItem
components as children. Provide a label
and placeholder
. Each SelectItem
requires a unique itemKey
and textValue
(for display in the trigger when selected).
1<Select label="Favorite Animal" placeholder="Pick an animal">
2 <SelectItem itemKey="cat" textValue="Cat">Cat</SelectItem>
3 <SelectItem itemKey="dog" textValue="Dog">Dog</SelectItem>
4 <SelectItem itemKey="dragon" textValue="Dragon">Dragon</SelectItem>
5 <SelectItem itemKey="kangaroo" textValue="Kangaroo" isDisabled>Kangaroo (Disabled)</SelectItem>
6</Select>
Dynamic Items
Use the items
array and renderItem
function to dynamically generate select options.
1const animals = [
2 { id: 'lion', name: 'Lion', family: 'Felidae' },
3 { id: 'tiger', name: 'Tiger', family: 'Felidae' },
4 { id: 'bear', name: 'Bear', family: 'Ursidae' },
5 { id: 'wolf', name: 'Wolf', family: 'Canidae', isDisabled: true },
6];
7
8<Select
9 label="Choose an Animal (Dynamic)"
10 placeholder="Select from list"
11 items={animals}
12 renderItem={(item) => (
13 <SelectItem
14 itemKey={item.id}
15 textValue={item.name} // Important for display in trigger
16 isDisabled={item.isDisabled}
17 description={item.family}
18 >
19 {item.name}
20 </SelectItem>
21 )}
22/>
Selection Modes
Supports single
(default) or multiple
selection via the selectionMode
prop.
1<View style={{gap: 20}}>
2 <Select label="Single Selection (Default)" placeholder="Choose one">
3 <SelectItem itemKey="s1">Option 1</SelectItem>
4 <SelectItem itemKey="s2">Option 2</SelectItem>
5 </Select>
6 <Select label="Multiple Selection" selectionMode="multiple" placeholder="Choose many">
7 <SelectItem itemKey="m1">Option A</SelectItem>
8 <SelectItem itemKey="m2">Option B</SelectItem>
9 <SelectItem itemKey="m3">Option C</SelectItem>
10 </Select>
11</View>
Controlled and Uncontrolled Selection
Manage selection state with selectedKeys
and onSelectionChange
, or use defaultSelectedKeys
for uncontrolled behavior.
1function ControlledSelect() {
2 const [selected, setSelected] = React.useState(new Set(['mars']));
3
4 return (
5 <View style={{gap: 8}}>
6 <Select
7 label="Select Planet (Controlled)"
8 selectedKeys={selected}
9 onSelectionChange={setSelected}
10 selectionMode="single" // or "multiple"
11 >
12 <SelectItem itemKey="earth">Earth</SelectItem>
13 <SelectItem itemKey="mars">Mars</SelectItem>
14 <SelectItem itemKey="jupiter">Jupiter</SelectItem>
15 </Select>
16 <Text>Selected: {Array.from(selected).join(', ')}</Text>
17 </View>
18 );
19}
20
21// Uncontrolled (uses defaultSelectedKeys)
22// <Select label="Select Color (Uncontrolled)" defaultSelectedKeys={['red']}>
23// <SelectItem itemKey="red">Red</SelectItem>
24// <SelectItem itemKey="blue">Blue</SelectItem>
25// </Select>
26
Label, Description, and Error Message
Use label
, description
, isInvalid
, and errorMessage
for context and validation feedback. labelPlacement
(default: 'outside') controls label position.
1<View style={{gap: 16}}>
2 <Select
3 label="Email Preferences"
4 description="Choose how often you want to receive emails."
5 placeholder="Select frequency"
6 >
7 <SelectItem itemKey="daily">Daily</SelectItem>
8 <SelectItem itemKey="weekly">Weekly</SelectItem>
9 </Select>
10 <Select
11 label="Confirm Age"
12 placeholder="Select an option"
13 isInvalid
14 errorMessage="You must select an option to proceed."
15 // selectedKeys={new Set()} // To show error state with no selection
16 >
17 <SelectItem itemKey="yes">Yes, I am over 18</SelectItem>
18 <SelectItem itemKey="no">No, I am not</SelectItem>
19 </Select>
20</View>
Trigger Variants
The trigger button supports bordered
(default), flat
, faded
, and underlined
variants.
1<View style={{gap: 16}}>
2 <Select label="Variant: Bordered (Default)" placeholder="Bordered">
3 <SelectItem itemKey="1">Option 1</SelectItem>
4 </Select>
5 <Select label="Variant: Flat" variant="flat" placeholder="Flat">
6 <SelectItem itemKey="1">Option 1</SelectItem>
7 </Select>
8 <Select label="Variant: Faded" variant="faded" placeholder="Faded">
9 <SelectItem itemKey="1">Option 1</SelectItem>
10 </Select>
11 <Select label="Variant: Underlined" variant="underlined" placeholder="Underlined">
12 <SelectItem itemKey="1">Option 1</SelectItem>
13 </Select>
14</View>
Trigger Sizes
Adjust trigger size with sm
, md
(default), or lg
.
1<View style={{gap: 16}}>
2 <Select label="Size: Small" size="sm" placeholder="Small Select">
3 <SelectItem itemKey="1">Option 1</SelectItem>
4 </Select>
5 <Select label="Size: Medium (Default)" size="md" placeholder="Medium Select">
6 <SelectItem itemKey="1">Option 1</SelectItem>
7 </Select>
8 <Select label="Size: Large" size="lg" placeholder="Large Select">
9 <SelectItem itemKey="1">Option 1</SelectItem>
10 </Select>
11</View>
Trigger Radius
Control trigger border radius with none
, sm
, md
(default), lg
, or full
.
1<View style={{gap: 16}}>
2 <Select label="Radius: None" radius="none" placeholder="No Radius">
3 <SelectItem itemKey="1">Option 1</SelectItem>
4 </Select>
5 <Select label="Radius: Medium (Default)" radius="md" placeholder="Medium Radius">
6 <SelectItem itemKey="1">Option 1</SelectItem>
7 </Select>
8 <Select label="Radius: Full" radius="full" placeholder="Full Radius">
9 <SelectItem itemKey="1">Option 1</SelectItem>
10 </Select>
11</View>
Trigger Colors
The color
prop influences the trigger's appearance on focus or when invalid. It also sets the default listboxColor
.
1<View style={{gap: 16}}>
2 <Select label="Color: Primary" color="primary" placeholder="Primary Focus">
3 <SelectItem itemKey="1">Option 1</SelectItem>
4 </Select>
5 <Select label="Color: Success" color="success" placeholder="Success Focus">
6 <SelectItem itemKey="1">Option 1</SelectItem>
7 </Select>
8 <Select label="Color: Danger (Invalid)" color="danger" isInvalid errorMessage="Error!" placeholder="Danger Focus">
9 <SelectItem itemKey="1">Option 1</SelectItem>
10 </Select>
11</View>
Start and End Content (Trigger)
Add icons or other elements to the trigger using startContent
and endContent
.
1<View style={{gap: 16}}>
2 <Select
3 label="Search City"
4 placeholder="Select city"
5 startContent={<Icon name="search" size={20} color="gray" />}
6 >
7 <SelectItem itemKey="ny">New York</SelectItem>
8 <SelectItem itemKey="ldn">London</SelectItem>
9 </Select>
10 <Select
11 label="Currency"
12 placeholder="Select currency"
13 endContent={<Text style={{color: 'gray', fontSize: 14}}>USD</Text>}
14 defaultSelectedKeys={['usd']}
15 >
16 <SelectItem itemKey="usd" textValue="USD">US Dollar</SelectItem>
17 <SelectItem itemKey="eur" textValue="EUR">Euro</SelectItem>
18 </Select>
19</View>
Custom Selector Icon
Replace the default dropdown arrow with a custom icon using the selectorIcon
prop.
1<Select
2 label="Custom Icon"
3 placeholder="Pick one"
4 selectorIcon={<Icon name="keyboard-arrow-down" size={24} color="purple" />}
5>
6 <SelectItem itemKey="a">Alpha</SelectItem>
7 <SelectItem itemKey="b">Beta</SelectItem>
8</Select>
Controlled Open State
Manage the listbox's visibility with isOpen
and onOpenChange
, or use defaultOpen
.
1function ControlledOpenSelect() {
2 const [isOpen, setIsOpen] = React.useState(false);
3 return (
4 <View style={{gap: 8}}>
5 <CrossBuildButton onPress={() => setIsOpen(!isOpen)}>
6 {isOpen ? 'Close Select' : 'Open Select'}
7 </CrossBuildButton>
8 <Select
9 label="My Select"
10 isOpen={isOpen}
11 onOpenChange={setIsOpen}
12 placeholder="Controlled Open State"
13 >
14 <SelectItem itemKey="1">Item One</SelectItem>
15 <SelectItem itemKey="2">Item Two</SelectItem>
16 </Select>
17 </View>
18 );
19}
Disabled State
Disable the entire Select component with disabled
. Individual items can be disabled using disabledKeys
or the isDisabled
prop on SelectItem
.
1<Select label="Completely Disabled Select" placeholder="Cannot open" disabled>
2 <SelectItem itemKey="x">X</SelectItem>
3</Select>
Listbox Customization
Customize the appearance and behavior of the dropdown listbox using listboxColor
, listboxVariant
, maxListboxHeight
, showScrollIndicators
, and disableAnimation
.
1<Select
2 label="Customized Listbox"
3 placeholder="Open to see"
4 listboxColor="secondary" // Affects item selection background, etc.
5 listboxVariant="flat" // Affects listbox background and border
6 maxListboxHeight={150} // Custom max height for the dropdown
7>
8 <SelectItem itemKey="opt1">Option 1</SelectItem>
9 <SelectItem itemKey="opt2">Option 2</SelectItem>
10 <SelectItem itemKey="opt3">Option 3</SelectItem>
11 <SelectItem itemKey="opt4">Option 4</SelectItem>
12</Select>
Virtualization
For long lists, virtualization is enabled by default if item count > 50. You can control it with isVirtualized
and optimize performance by providing itemHeight
. Additional FlatList
props can be passed via flatListProps
.
1const manyItems = Array.from({ length: 100 }, (_, i) => ({ id: `item-${i}`, name: `Item ${i + 1}` }));
2
3<Select
4 label="Virtualized Select (100 items)"
5 placeholder="Scroll to see more"
6 items={manyItems}
7 renderItem={(item) => <SelectItem itemKey={item.id} textValue={item.name}>{item.name}</SelectItem>}
8 itemHeight={40} // Important for performance with isVirtualized
9 // isVirtualized is true by default if items.length > 50
10 // isVirtualized
11 maxListboxHeight={200}
12/>
Styling Select
Customize Select slots using the styles
prop: base
, label
, trigger
, value
, placeholder
, description
, errorMessage
, startContentWrapper
, endContentWrapper
, selectorIconWrapper
, listboxWrapper
. The main style
prop targets the base container.
1<Select
2 label="Styled Select Trigger"
3 placeholder="Styled placeholder"
4 style={{ marginVertical: 10 }} // Base container style
5 styles={{
6 base: { backgroundColor: '#f0f8ff' },
7 label: { color: 'navy', fontWeight: 'bold' },
8 trigger: { borderColor: 'teal', borderWidth: 2, backgroundColor: 'white' },
9 value: { color: 'purple', fontStyle: 'italic' }, // For selected value text
10 // placeholder: { color: 'lightgray' }, // Placeholder text color is handled by triggerTextColor logic
11 description: { color: 'green' },
12 listboxWrapper: { borderColor: 'darkorange', borderWidth: 1, borderRadius: 12 }
13 }}
14 description="This select has custom trigger and listbox styles."
15>
16 <SelectItem itemKey="s1">Styled Option 1</SelectItem>
17</Select>
Select Props
PROP | TYPE | DEFAULT | DESCRIPTION |
---|---|---|---|
children | ReactNode | (item) => ReactElement | - | Static items or render function for dynamic items. |
items | T[] | - | Array of data for dynamic items. |
renderItem | (item: T) => ReactElement | - | Function to render each dynamic item. |
selectionMode | 'single' | 'multiple' | 'single' | Selection behavior. |
selectedKeys | Iterable<string | number> | - | Controlled selected item keys. |
defaultSelectedKeys | Iterable<string | number> | - | Initial selected keys (uncontrolled). |
onSelectionChange | (keys: Set<string | number>) => void | - | Callback when selection changes. |
disabledKeys | Iterable<string | number> | - | Keys of items to disable. |
variant | SelectVariant | 'bordered' | Trigger visual style. |
color | SelectColor | 'default' | Trigger color, listbox default. |
size | SelectSize | 'md' | Trigger size. |
radius | SelectRadius | 'md' | Trigger border radius. |
placeholder | string | "Select an option" | Placeholder text for the trigger. |
labelPlacement | SelectLabelPlacement | 'outside' | Position of the label. |
label | ReactNode | - | Label for the select. |
description | ReactNode | - | Helper text below the select. |
errorMessage | ReactNode | - | Error message when isInvalid . |
isInvalid | boolean | false | Marks select as invalid. |
startContent | ReactNode | - | Content at the start of the trigger. |
endContent | ReactNode | - | Content at the end of the trigger. |
selectorIcon | ReactNode | - | Custom dropdown indicator icon. |
maxListboxHeight | number | string | - | Max height of the listbox. |
itemHeight | number | - | Height of each item for virtualization. |
isVirtualized | boolean | Auto | Enable/disable virtualization. Auto if items > 50. |
isOpen | boolean | - | Controlled open state of the listbox. |
defaultOpen | boolean | false | Initial open state (uncontrolled). |
onOpenChange | (isOpen: boolean) => void | - | Callback when listbox open state changes. |
isMultiline | boolean | false | Allow trigger value to wrap. |
showScrollIndicators | boolean | true | Show scroll indicators in listbox. |
disableAnimation | boolean | false | Disable listbox open/close animation. |
style | StyleProp<ViewStyle> | - | Style for the base container. |
styles | SelectSlotsStyles | - | Custom styles for select slots. |
disabled | boolean | false | Disable the entire select. |
flatListProps | Partial<FlatListProps> | - | Props for the internal FlatList. |
itemStyle | Partial<SelectItemSlots> | - | Default styles for all listbox items. |
listboxColor | SelectColor | Trigger color | Color theme for the listbox. |
listboxVariant | SelectVariant | 'light' | Visual style for the listbox. |
SelectItem Component
Represents an individual option within the Select.
Item Features
SelectItem
supports description
, startContent
, endContent
, custom selectedIcon
, and more.
1<Select label="Item Features" placeholder="Explore items">
2 <SelectItem itemKey="basic" textValue="Basic">Basic Item</SelectItem>
3 <SelectItem
4 itemKey="desc"
5 textValue="With Description"
6 description="This item has a helpful description."
7 >
8 Item with Description
9 </SelectItem>
10 <SelectItem
11 itemKey="content"
12 textValue="With Start/End Content"
13 startContent={<Icon name="star" size={18} color="orange" />}
14 endContent={<Icon name="info" size={18} color="blue" />}
15 >
16 Item with Start/End Content
17 </SelectItem>
18 <SelectItem itemKey="noicon" textValue="No Selected Icon" hideSelectedIcon>
19 No Selected Icon
20 </SelectItem>
21 <SelectItem itemKey="customicon" textValue="Custom Icon" selectedIcon={<Icon name="favorite" size={20} color="red" />}>
22 Custom Selected Icon
23 </SelectItem>
24 <SelectItem itemKey="divider" textValue="With Divider" showDivider>
25 Item with Divider
26 </SelectItem>
27</Select>
Styling SelectItem
Customize SelectItem
slots: base
, wrapper
, title
, description
, startContentWrapper
, endContentWrapper
, selectedIconWrapper
, divider
. The main style
prop targets the Pressable base.
1<Select label="Styled Items" placeholder="Open me">
2 <SelectItem
3 itemKey="custom1"
4 textValue="Custom Item 1"
5 style={{ backgroundColor: '#e6ffe6' }} // Pressable style
6 slotStyles={{
7 base: { paddingVertical: 15 },
8 title: { color: 'darkgreen', fontWeight: 'bold' },
9 description: { color: 'limegreen' },
10 startContentWrapper: { paddingRight: 15 }
11 }}
12 description="This item is heavily styled."
13 startContent={<Icon name="eco" size={20} color="green" />}
14 >
15 Custom Item 1
16 </SelectItem>
17 <SelectItem itemKey="custom2" textValue="Custom Item 2">Default Item Style</SelectItem>
18</Select>
SelectItem Props
PROP | TYPE | DEFAULT | DESCRIPTION |
---|---|---|---|
itemKey | string | number | - | Unique key for the item. Required. |
children | ReactNode | - | Primary display content, overrides title . |
title | ReactNode | - | Title if children not provided. |
textValue | string | - | Text representation for trigger display and accessibility. Crucial. |
description | ReactNode | - | Additional descriptive text. |
startContent | ReactNode | - | Content before the main text. |
endContent | ReactNode | - | Content after the main text, before selected icon. |
selectedIcon | ReactNode | (props) => ReactNode | Default Icon | Custom icon for selected state. |
showDivider | boolean | false | Show a divider after this item. |
hideSelectedIcon | boolean | Contextual | Hide the selected checkmark icon. |
style | StyleProp<ViewStyle> | - | Style for the Pressable base. |
slotStyles | Partial<SelectItemSlots> | - | Custom styles for item slots. |
isDisabled | boolean | false | Disable this item. |
SelectSection Component
Groups related SelectItem
components with an optional title.
Grouping Items
Use SelectSection
to organize items. Each section requires an itemKey
.
1<Select label="Categorized Options" placeholder="Select a framework">
2 <SelectSection itemKey="frontend" title="Frontend Frameworks">
3 <SelectItem itemKey="react" textValue="React">React.js</SelectItem>
4 <SelectItem itemKey="vue" textValue="Vue">Vue.js</SelectItem>
5 </SelectSection>
6 <SelectSection itemKey="backend" title="Backend Frameworks" showDivider>
7 <SelectItem itemKey="express" textValue="Express">Express.js</SelectItem>
8 <SelectItem itemKey="django" textValue="Django">Django</SelectItem>
9 </SelectSection>
10 <SelectItem itemKey="other" textValue="Other">Other</SelectItem>
11</Select>
Styling SelectSection
The style
prop targets the section's base View. itemStyle
on SelectSection
can provide contextual styling for items within it.
1<Select label="Styled Sections" placeholder="View sections">
2 <SelectSection
3 itemKey="sec1"
4 title="Custom Section Title"
5 style={{ backgroundColor: '#fff0f5', paddingBottom: 10 }} // View style for section base
6 // Section has limited direct styleable slots, mostly for title and divider
7 // itemStyle prop on SelectSection can style items within it
8 itemStyle={{ base: { backgroundColor: '#fafad2' }, title: {color: 'goldenrod'} }}
9 showDivider
10 // dividerProps={{ style: { backgroundColor: 'pink', height: 2 } }}
11 >
12 <SelectItem itemKey="sec1opt1" textValue="Option A1">Option A1 (Styled by Section)</SelectItem>
13 </SelectSection>
14 <SelectSection itemKey="sec2" title="Another Section">
15 <SelectItem itemKey="sec2opt1" textValue="Option B1">Option B1</SelectItem>
16 </SelectSection>
17</Select>
SelectSection Props
PROP | TYPE | DEFAULT | DESCRIPTION |
---|---|---|---|
itemKey | string | number | - | Unique key for the section. Required. |
children | ReactNode | - | The SelectItem components within this section. |
title | string | - | Title displayed above the section items. |
hideSelectedIcon | boolean | Contextual | Contextual prop to hide selected icons for items in this section. |
showDivider | boolean | false | Show a divider after this section. |
dividerProps | StyleProp<ViewStyle> | - | Custom styles for the section divider. |
style | StyleProp<ViewStyle> | - | Style for the section's base View. |
itemStyle | Partial<SelectItemSlots> | - | Contextual styles for items within this section. |
Accessibility
The Select component aims for good accessibility:
- The trigger has
accessibilityRole="combobox"
andaccessibilityState= expanded:isListboxOpen
. SelectItem
components haveaccessibilityRole="menuitem"
and appropriateaccessibilityState
.- The
label
prop onSelect
is crucial for context. - The
textValue
prop onSelectItem
is used foraccessibilityLabel
if the item's children are not simple strings. - Keyboard navigation within the listbox is handled by
FlatList
.