Listbox

The Listbox component allows users to select one or more items from a list. It can be used to build menus, select inputs, and other list-based UIs.

Installation

$ cbui-cli install @crossbuildui/listbox

Import

index.tsx
1import { Listbox, ListboxItem, ListboxSection } from '@/crossbuildui/listbox'; 2// import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; // If using icons 3// import { View, Text } from 'react-native'; // For content

Basic Usage

Create a listbox by nesting ListboxItem components within a Listbox container. Each item needs a unique itemKey.

index.tsx
1<Listbox aria-label="Basic Listbox Example"> 2 <ListboxItem itemKey="item1">Item One</ListboxItem> 3 <ListboxItem itemKey="item2">Item Two</ListboxItem> 4 <ListboxItem itemKey="item3">Item Three</ListboxItem> 5</Listbox>

With Sections

Organize items into groups using the ListboxSection component. Sections can have titles and optional dividers.

index.tsx
1<Listbox aria-label="Listbox with Sections"> 2 <ListboxSection title="Actions" itemKey="actions-section"> 3 <ListboxItem itemKey="new">New file</ListboxItem> 4 <ListboxItem itemKey="copy">Copy link</ListboxItem> 5 <ListboxItem itemKey="edit">Edit file</ListboxItem> 6 </ListboxSection> 7 <ListboxSection title="Danger Zone" itemKey="danger-section" showDivider> 8 <ListboxItem itemKey="delete" style={{color: 'red'}}>Delete file</ListboxItem> 9 </ListboxSection> 10</Listbox>

Selection Modes

Control selection behavior with selectionMode: 'single', 'multiple', or 'none'. Use defaultSelectedKeys for uncontrolled initial selection or selectedKeys for controlled selection.

index.tsx
1// Single Selection (default behavior if selectionMode is not 'none') 2<Listbox selectionMode="single" defaultSelectedKeys={["cat"]}> 3 <ListboxItem itemKey="dog">Dog</ListboxItem> 4 <ListboxItem itemKey="cat">Cat</ListboxItem> 5 <ListboxItem itemKey="mouse">Mouse</ListboxItem> 6</Listbox> 7 8// Multiple Selection 9<Listbox selectionMode="multiple" defaultSelectedKeys={["apple", "orange"]}> 10 <ListboxItem itemKey="apple">Apple</ListboxItem> 11 <ListboxItem itemKey="banana">Banana</ListboxItem> 12 <ListboxItem itemKey="orange">Orange</ListboxItem> 13</Listbox> 14 15// No Selection 16<Listbox selectionMode="none"> 17 <ListboxItem itemKey="view">View Details</ListboxItem> 18 <ListboxItem itemKey="info">Information</ListboxItem> 19</Listbox>

Disabled Items & Listbox

Disable specific items using the disabledKeys prop on Listbox or the isDisabled prop on ListboxItem. The entire Listbox can be disabled using its disabled prop.

index.tsx
1<Listbox disabledKeys={["edit"]}> 2 <ListboxItem itemKey="new">New File</ListboxItem> 3 <ListboxItem itemKey="copy">Copy Link</ListboxItem> 4 <ListboxItem itemKey="edit">Edit File (Disabled)</ListboxItem> 5 <ListboxItem itemKey="delete" isDisabled>Delete File (Explicitly Disabled)</ListboxItem> 6</Listbox> 7 8// Entire Listbox disabled 9<Listbox disabled defaultSelectedKeys={["one"]}> 10 <ListboxItem itemKey="one">One</ListboxItem> 11 <ListboxItem itemKey="two">Two</ListboxItem> 12</Listbox>

Item Content & Structure

ListboxItem supports title, description, startContent, endContent, and custom selectedIcon. Providing children to ListboxItem will override the title.

index.tsx
1<Listbox> 2 <ListboxItem 3 itemKey="profile" 4 title="User Profile" 5 description="Manage your account settings" 6 startContent={<Icon name="account-circle-outline" size={24} />} 7 endContent={<Icon name="chevron-right" size={20} />} 8 > 9 {/* Children override title, so title prop is ignored here */} 10 <View><Text style={{fontWeight: 'bold'}}>Custom Profile View</Text></View> 11 </ListboxItem> 12 <ListboxItem 13 itemKey="notifications" 14 title="Notifications" 15 description="Configure alerts" 16 startContent={<Icon name="bell-outline" size={24} />} 17 selectedIcon={<Icon name="star" size={20} color="gold" />} 18 /> 19</Listbox>

Variants & Colors

Listbox supports solid, bordered, light, flat, faded, and shadow variants. Apply thematic colors using the color prop.

index.tsx
1<View style={{flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-around'}}> 2 <Listbox variant="solid" color="primary" defaultSelectedKeys={["s1"]} style={{margin:5, width: 150}}> 3 <ListboxItem itemKey="s1">Solid Primary</ListboxItem> 4 </Listbox> 5 <Listbox variant="bordered" color="secondary" defaultSelectedKeys={["b1"]} style={{margin:5, width: 150}}> 6 <ListboxItem itemKey="b1">Bordered Secondary</ListboxItem> 7 </Listbox> 8 <Listbox variant="light" color="success" defaultSelectedKeys={["l1"]} style={{margin:5, width: 150}}> 9 <ListboxItem itemKey="l1">Light Success</ListboxItem> 10 </Listbox> 11 <Listbox variant="flat" color="warning" defaultSelectedKeys={["f1"]} style={{margin:5, width: 150}}> 12 <ListboxItem itemKey="f1">Flat Warning</ListboxItem> 13 </Listbox> 14 <Listbox variant="faded" color="danger" defaultSelectedKeys={["fd1"]} style={{margin:5, width: 150}}> 15 <ListboxItem itemKey="fd1">Faded Danger</ListboxItem> 16 </Listbox> 17 <Listbox variant="shadow" color="default" defaultSelectedKeys={["sh1"]} style={{margin:5, width: 150}}> 18 <ListboxItem itemKey="sh1">Shadow Default</ListboxItem> 19 </Listbox> 20</View>

Dynamic Items

Render items dynamically by providing an items array and a renderItem function, or by passing a function as children.

index.tsx
1const users = [ 2 { id: '1', name: 'Alice', avatar: 'https://i.pravatar.cc/150?u=alice' }, 3 { id: '2', name: 'Bob', avatar: 'https://i.pravatar.cc/150?u=bob' }, 4 { id: '3', name: 'Charlie', avatar: 'https://i.pravatar.cc/150?u=charlie' }, 5]; 6 7<Listbox 8 items={users} 9 renderItem={(user) => ( 10 <ListboxItem 11 itemKey={user.id} 12 title={user.name} 13 startContent={<Image source={{ uri: user.avatar }} style={{ width: 30, height: 30, borderRadius: 15 }} />} 14 /> 15 )} 16 aria-label="User List" 17/> 18 19// Alternative with children as a function 20<Listbox items={users} aria-label="User List Alt"> 21 {(user) => ( 22 <ListboxItem 23 itemKey={user.id} 24 title={user.name} 25 description={`User ID: ${user.id}`} 26 /> 27 )} 28</Listbox>

Top & Bottom Content

Add custom content at the beginning or end of the list using topContent and bottomContent props.

index.tsx
1<Listbox topContent={<Text style={{padding:10, fontWeight:'bold'}}>Available Options</Text>} 2 bottomContent={<Text style={{padding:10, fontSize:10, textAlign:'center'}}>End of list</Text>}> 3 <ListboxItem itemKey="opt1">Option 1</ListboxItem> 4 <ListboxItem itemKey="opt2">Option 2</ListboxItem> 5</Listbox>

Empty State

Display custom content when the list is empty using the emptyContent prop.

index.tsx
1<Listbox items={[]} emptyContent={<View style={{padding:20, alignItems:'center'}}><Text>No data found.</Text></View>}> 2 {(item) => <ListboxItem itemKey={item.id}>{item.name}</ListboxItem>} 3</Listbox>

Props Overview

Listbox Props

PROPTYPEDEFAULTDESCRIPTION
childrenReactNode | (item) => ReactElement-Static items or render function for dynamic items.
itemsT[]-Array of data for dynamic rendering.
renderItem(item: T) => ReactElement-Function to render each item from the items array.
variantListboxVariant'solid'Visual style.
colorListboxColor'default'Thematic color.
selectionModeListboxSelectionMode'none'Selection behavior.
selectedKeysIterable<string|number>-Controlled selected item keys.
defaultSelectedKeysIterable<string|number>[]Initially selected keys (uncontrolled).
disabledKeysIterable<string|number>[]Keys of disabled items.
disallowEmptySelectionbooleanfalsePrevent deselection if it results in no selection.
topContentReactNode-Content displayed above the list items.
bottomContentReactNode-Content displayed below the list items.
emptyContentReactNode"No items."Content displayed when list is empty.
hideSelectedIconbooleanfalseHide selected state icon globally.
styleStyleProp<ViewStyle>-Style for the Listbox container.
itemStylePartial<ListboxItemSlots>-Global styles for all ListboxItem slots.
onSelectionChange(keys: Set<string|number>) => void-Callback when selection changes.
disabledbooleanfalseDisable the entire Listbox.

ListboxItem Props

PROPTYPEDEFAULTDESCRIPTION
childrenReactNode-Custom content, overrides title.
itemKeystring | number-Unique key for the item. **Required.**
titleReactNode-Primary text content of the item.
textValuestring-Plain text representation for accessibility/typeahead.
descriptionReactNode-Secondary text content below the title.
startContentReactNode-Content displayed before the main text.
endContentReactNode-Content displayed after the selected icon (if visible).
selectedIconReactNode | (props) => ReactNodeDefault IconCustom icon for selected state.
showDividerbooleanfalseShow a divider below this item.
hideSelectedIconbooleanContextualOverride Listbox/Section setting for this item.
styleStyleProp<ViewStyle>-Style for the item's outer Pressable.
slotStylesPartial<ListboxItemSlots>-Styles for inner parts of the item (title, description, etc.).
isDisabledbooleanfalseExplicitly disable this item.

ListboxSection Props

PROPTYPEDEFAULTDESCRIPTION
childrenReactNode-ListboxItem components within this section.
itemKeystring | number-Unique key for the section. Required.
titlestring-Title displayed above the section items.
hideSelectedIconbooleanContextualOverride Listbox's hideSelectedIcon for items in this section.
showDividerbooleanfalseShow a divider after the section.
dividerPropsStyleProp<ViewStyle>-Custom style for the section divider.
styleStyleProp<ViewStyle>-Style for the section container.
itemStylePartial<ListboxItemSlots>-Styles for ListboxItem slots within this section, overrides Listbox's itemStyle.

Styling

Customize appearance using:

  • Listbox:
    • style: For the main Listbox container (View).
    • itemStyle: Global styles for all ListboxItem slots (e.g., base, title, description).
  • ListboxSection:
    • style: For the section wrapper View.
    • itemStyle: Styles for ListboxItem slots within this section, overriding Listbox's itemStyle.
    • dividerProps: Style for the section's bottom divider.
  • ListboxItem:
    • style: For the item's root Pressable component.
    • slotStyles: Specific styles for inner parts of this item (e.g., wrapper, title, startContentWrapper), overriding section and Listbox itemStyle.

Style precedence for item slots: ListboxItem.slotStyles > ListboxSection.itemStyle > Listbox.itemStyle.

index.tsx
1<Listbox 2 style={{ marginVertical: 10, borderColor: 'purple', borderWidth: 1, borderRadius: 12 }} // Styles the Listbox container 3 itemStyle={{ // Global styles for all ListboxItem slots 4 base: { paddingVertical: 15 }, 5 title: { fontWeight: '600', color: 'navy' }, 6 description: { fontStyle: 'italic' } 7 }} 8 variant="flat" 9 color="primary" 10> 11 <ListboxSection 12 title="Custom Section" 13 itemKey="custom-sec" 14 style={{ backgroundColor: 'rgba(200,200,255,0.3)' }} 15 itemStyle={{ // Overrides Listbox's itemStyle for this section 16 title: { color: 'darkgreen' } 17 }} 18 > 19 <ListboxItem 20 itemKey="styled1" 21 title="Item with Specific Slot Styles" 22 slotStyles={{ // Styles for slots of this specific item 23 base: { borderLeftWidth: 3, borderLeftColor: 'orange' }, 24 wrapper: { paddingLeft: 10 }, 25 title: { textDecorationLine: 'underline', color: 'red' } // Overrides section and listbox itemStyle 26 }} 27 style={{ backgroundColor: 'lightyellow' }} // Style for the Pressable of this item 28 /> 29 <ListboxItem itemKey="styled2" title="Section Styled Item" description="Inherits from section" /> 30 </ListboxSection> 31 <ListboxItem itemKey="styled3" title="Listbox Styled Item" description="Inherits from listbox" /> 32</Listbox>

Accessibility

The Listbox components are designed with accessibility in mind:

  • Listbox container has accessibilityRole="list".
  • Each ListboxItem has accessibilityRole="menuitem" (can be adjusted if used as a general selectable list).
  • ListboxItem includes accessibilityState for selected and disabled states.
  • ListboxItem uses textValue or title for its accessibilityLabel.