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

Import

index.tsx
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).

MyComponent.tsx
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.

MyComponent.tsx
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.

MyComponent.tsx
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.

MyComponent.tsx
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.

MyComponent.tsx
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.

MyComponent.tsx
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.

MyComponent.tsx
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.

MyComponent.tsx
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.

MyComponent.tsx
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.

MyComponent.tsx
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.

MyComponent.tsx
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.

MyComponent.tsx
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.

MyComponent.tsx
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.

MyComponent.tsx
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.

MyComponent.tsx
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.

MyComponent.tsx
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

PROPTYPEDEFAULTDESCRIPTION
childrenReactNode | (item) => ReactElement-Static items or render function for dynamic items.
itemsT[]-Array of data for dynamic items.
renderItem(item: T) => ReactElement-Function to render each dynamic item.
selectionMode'single' | 'multiple''single'Selection behavior.
selectedKeysIterable<string | number>-Controlled selected item keys.
defaultSelectedKeysIterable<string | number>-Initial selected keys (uncontrolled).
onSelectionChange(keys: Set<string | number>) => void-Callback when selection changes.
disabledKeysIterable<string | number>-Keys of items to disable.
variantSelectVariant'bordered'Trigger visual style.
colorSelectColor'default'Trigger color, listbox default.
sizeSelectSize'md'Trigger size.
radiusSelectRadius'md'Trigger border radius.
placeholderstring"Select an option"Placeholder text for the trigger.
labelPlacementSelectLabelPlacement'outside'Position of the label.
labelReactNode-Label for the select.
descriptionReactNode-Helper text below the select.
errorMessageReactNode-Error message when isInvalid.
isInvalidbooleanfalseMarks select as invalid.
startContentReactNode-Content at the start of the trigger.
endContentReactNode-Content at the end of the trigger.
selectorIconReactNode-Custom dropdown indicator icon.
maxListboxHeightnumber | string-Max height of the listbox.
itemHeightnumber-Height of each item for virtualization.
isVirtualizedbooleanAutoEnable/disable virtualization. Auto if items > 50.
isOpenboolean-Controlled open state of the listbox.
defaultOpenbooleanfalseInitial open state (uncontrolled).
onOpenChange(isOpen: boolean) => void-Callback when listbox open state changes.
isMultilinebooleanfalseAllow trigger value to wrap.
showScrollIndicatorsbooleantrueShow scroll indicators in listbox.
disableAnimationbooleanfalseDisable listbox open/close animation.
styleStyleProp<ViewStyle>-Style for the base container.
stylesSelectSlotsStyles-Custom styles for select slots.
disabledbooleanfalseDisable the entire select.
flatListPropsPartial<FlatListProps>-Props for the internal FlatList.
itemStylePartial<SelectItemSlots>-Default styles for all listbox items.
listboxColorSelectColorTrigger colorColor theme for the listbox.
listboxVariantSelectVariant'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.

MyComponent.tsx
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.

MyComponent.tsx
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

PROPTYPEDEFAULTDESCRIPTION
itemKeystring | number-Unique key for the item. Required.
childrenReactNode-Primary display content, overrides title.
titleReactNode-Title if children not provided.
textValuestring-Text representation for trigger display and accessibility. Crucial.
descriptionReactNode-Additional descriptive text.
startContentReactNode-Content before the main text.
endContentReactNode-Content after the main text, before selected icon.
selectedIconReactNode | (props) => ReactNodeDefault IconCustom icon for selected state.
showDividerbooleanfalseShow a divider after this item.
hideSelectedIconbooleanContextualHide the selected checkmark icon.
styleStyleProp<ViewStyle>-Style for the Pressable base.
slotStylesPartial<SelectItemSlots>-Custom styles for item slots.
isDisabledbooleanfalseDisable this item.

SelectSection Component

Groups related SelectItem components with an optional title.

Grouping Items

Use SelectSection to organize items. Each section requires an itemKey.

MyComponent.tsx
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.

MyComponent.tsx
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

PROPTYPEDEFAULTDESCRIPTION
itemKeystring | number-Unique key for the section. Required.
childrenReactNode-The SelectItem components within this section.
titlestring-Title displayed above the section items.
hideSelectedIconbooleanContextualContextual prop to hide selected icons for items in this section.
showDividerbooleanfalseShow a divider after this section.
dividerPropsStyleProp<ViewStyle>-Custom styles for the section divider.
styleStyleProp<ViewStyle>-Style for the section's base View.
itemStylePartial<SelectItemSlots>-Contextual styles for items within this section.

Accessibility

The Select component aims for good accessibility:

  • The trigger has accessibilityRole="combobox" and accessibilityState= expanded:isListboxOpen.
  • SelectItem components have accessibilityRole="menuitem" and appropriate accessibilityState.
  • The label prop on Select is crucial for context.
  • The textValue prop on SelectItem is used for accessibilityLabel if the item's children are not simple strings.
  • Keyboard navigation within the listbox is handled by FlatList.