SelectUpdated
Displays a list of options for the user to pick from — triggered by a button.
Import
import { Select } from 'heroui-native';Anatomy
<Select>
<Select.Trigger>
<Select.Value />
<Select.TriggerIndicator />
</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content>
<Select.Close />
<Select.ListLabel>...</Select.ListLabel>
<Select.Item>
<Select.ItemLabel />
<Select.ItemDescription>...</Select.ItemDescription>
<Select.ItemIndicator />
</Select.Item>
</Select.Content>
</Select.Portal>
</Select>- Select: Main container that manages open/close state, value selection and provides context to child components.
- Select.Trigger: Clickable element that toggles the select visibility. Wraps any child element with press handlers. Supports
variantprop ('default'or'unstyled'). - Select.Value: Displays the selected value or placeholder text. Automatically updates when selection changes. Styling changes based on selection state.
- Select.TriggerIndicator: Optional visual indicator showing open/close state. Renders an animated chevron icon by default that rotates when the select opens/closes.
- Select.Portal: Renders select content in a portal layer above other content. Ensures proper stacking and positioning.
- Select.Overlay: Optional background overlay. Can be transparent or semi-transparent to capture outside clicks.
- Select.Content: Container for select content with three presentation modes: popover (floating with positioning), bottom sheet modal, or dialog modal.
- Select.Close: Close button for the select. Can accept custom children or uses default close icon.
- Select.ListLabel: Label for the list of items with pre-styled typography.
- Select.Item: Selectable option item. Handles selection state and press events.
- Select.ItemLabel: Displays the label text for an item.
- Select.ItemDescription: Optional description text for items with muted styling.
- Select.ItemIndicator: Optional indicator shown for selected items. Renders a check icon by default.
Usage
Basic Usage
The Select component uses compound parts to create dropdown selection interfaces.
<Select>
<Select.Trigger>...</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="popover">
<Select.Item value="1" label="Option 1" />
<Select.Item value="2" label="Option 2" />
</Select.Content>
</Select.Portal>
</Select>With Value Display
Display the selected value in the trigger using the Value component.
<Select>
<Select.Trigger>
<Select.Value placeholder="Choose an option" />
<Select.TriggerIndicator />
</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="popover">
<Select.Item value="apple" label="Apple" />
<Select.Item value="orange" label="Orange" />
<Select.Item value="banana" label="Banana" />
</Select.Content>
</Select.Portal>
</Select>Popover Presentation
Use popover presentation for floating content with automatic positioning.
<Select>
<Select.Trigger>...</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="popover" placement="bottom" align="center">
<Select.Item value="1" label="Item 1" />
<Select.Item value="2" label="Item 2" />
</Select.Content>
</Select.Portal>
</Select>Width Control
Control the width of the select content using the width prop. This only works with popover presentation.
{
/* Fixed width in pixels */
}
<Select>
<Select.Trigger>...</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="popover" width={280}>
<Select.Item value="1" label="Item 1" />
</Select.Content>
</Select.Portal>
</Select>;
{
/* Match trigger width */
}
<Select>
<Select.Trigger>...</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="popover" width="trigger">
<Select.Item value="1" label="Item 1" />
</Select.Content>
</Select.Portal>
</Select>;
{
/* Full width (100%) */
}
<Select>
<Select.Trigger>...</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="popover" width="full">
<Select.Item value="1" label="Item 1" />
</Select.Content>
</Select.Portal>
</Select>;
{
/* Auto-size to content (default) */
}
<Select>
<Select.Trigger>...</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="popover" width="content-fit">
<Select.Item value="1" label="Item 1" />
</Select.Content>
</Select.Portal>
</Select>;Bottom Sheet Presentation
Use bottom sheet for mobile-optimized selection experience.
<Select presentation="bottom-sheet">
<Select.Trigger>...</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="bottom-sheet" snapPoints={['35%']}>
<Select.Item value="1" label="Item 1" />
<Select.Item value="2" label="Item 2" />
</Select.Content>
</Select.Portal>
</Select>Dialog Presentation
Use dialog presentation for centered modal-style selection.
<Select presentation="dialog">
<Select.Trigger>...</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="dialog">
<Select.Close />
<Select.ListLabel>Choose an option</Select.ListLabel>
<Select.Item value="1" label="Item 1" />
<Select.Item value="2" label="Item 2" />
</Select.Content>
</Select.Portal>
</Select>Custom Item Content
Customize item appearance with custom content and indicators.
<Select>
<Select.Trigger>...</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="popover">
<Select.Item value="us" label="United States">
<View className="flex-row items-center gap-3 flex-1">
<Text>🇺🇸</Text>
<Select.ItemLabel />
</View>
<Select.ItemIndicator />
</Select.Item>
<Select.Item value="uk" label="United Kingdom">
<View className="flex-row items-center gap-3 flex-1">
<Text>🇬🇧</Text>
<Select.ItemLabel />
</View>
<Select.ItemIndicator />
</Select.Item>
</Select.Content>
</Select.Portal>
</Select>With Render Function
Use a render function on Select.Item to access state and customize content based on selection.
<Select>
<Select.Trigger>...</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="popover">
<Select.Item value="us" label="United States">
{({ isSelected, value, isDisabled }) => (
<>
<View className="flex-row items-center gap-3 flex-1">
<Text>🇺🇸</Text>
<Select.ItemLabel
className={
isSelected ? 'text-accent font-medium' : 'text-foreground'
}
/>
</View>
<Select.ItemIndicator />
</>
)}
</Select.Item>
<Select.Item value="uk" label="United Kingdom">
{({ isSelected }) => (
<>
<View className="flex-row items-center gap-3 flex-1">
<Text>🇬🇧</Text>
<Select.ItemLabel
className={
isSelected ? 'text-accent font-medium' : 'text-foreground'
}
/>
</View>
<Select.ItemIndicator />
</>
)}
</Select.Item>
</Select.Content>
</Select.Portal>
</Select>With Item Description
Add descriptions to items for additional context.
<Select>
<Select.Trigger>...</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="popover">
<Select.Item value="basic" label="Basic">
<View className="flex-1">
<Select.ItemLabel />
<Select.ItemDescription>
Essential features for personal use
</Select.ItemDescription>
</View>
<Select.ItemIndicator />
</Select.Item>
</Select.Content>
</Select.Portal>
</Select>With Trigger Indicator
Add a visual indicator to show the open/close state of the select. The indicator rotates when the select opens/closes.
<Select>
<Select.Trigger>
<Select.Value placeholder="Select one" />
<Select.TriggerIndicator />
</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="popover">
<Select.Item value="1" label="Option 1" />
<Select.Item value="2" label="Option 2" />
</Select.Content>
</Select.Portal>
</Select>Custom Trigger with Unstyled Variant
Use the unstyled variant when composing a custom trigger with other components like Button.
<Select>
<Select.Trigger variant="unstyled" asChild>
<Button variant="secondary">
<Select.Value placeholder="Select..." />
<Select.TriggerIndicator />
</Button>
</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="popover">
<Select.Item value="1" label="Option 1" />
<Select.Item value="2" label="Option 2" />
</Select.Content>
</Select.Portal>
</Select>Controlled Mode
Control the select state programmatically.
const [value, setValue] = useState();
const [isOpen, setIsOpen] = useState(false);
<Select
value={value}
onValueChange={setValue}
isOpen={isOpen}
onOpenChange={setIsOpen}
>
<Select.Trigger>
<Select.Value placeholder="Select..." />
<Select.TriggerIndicator />
</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="popover">
<Select.Item value="1" label="Option 1" />
<Select.Item value="2" label="Option 2" />
</Select.Content>
</Select.Portal>
</Select>;Example
import { Select, Separator } from 'heroui-native';
import React, { useState } from 'react';
type SelectOption = {
value: string;
label: string;
};
const US_STATES: SelectOption[] = [
{ value: 'CA', label: 'California' },
{ value: 'NY', label: 'New York' },
{ value: 'TX', label: 'Texas' },
{ value: 'FL', label: 'Florida' },
];
export default function SelectExample() {
const [value, setValue] = useState<SelectOption | undefined>();
return (
<Select value={value} onValueChange={setValue}>
<Select.Trigger>
<Select.Value placeholder="Select one" />
<Select.TriggerIndicator />
</Select.Trigger>
<Select.Portal>
<Select.Overlay />
<Select.Content presentation="popover" width="trigger">
<Select.ListLabel className="mb-2">Choose a state</Select.ListLabel>
{US_STATES.map((state, index) => (
<React.Fragment key={state.value}>
<Select.Item value={state.value} label={state.label} />
{index < US_STATES.length - 1 && <Separator />}
</React.Fragment>
))}
</Select.Content>
</Select.Portal>
</Select>
);
}You can find more examples in the GitHub repository.
API Reference
Select
| prop | type | default | description |
|---|---|---|---|
children | ReactNode | - | The content of the select |
value | SelectOption | - | The selected value (controlled mode) |
onValueChange | (value: SelectOption) => void | - | Callback when the value changes |
defaultValue | SelectOption | - | The default selected value (uncontrolled mode) |
isOpen | boolean | - | Whether the select is open (controlled mode) |
isDefaultOpen | boolean | - | Whether the select is open when initially rendered (uncontrolled mode) |
onOpenChange | (isOpen: boolean) => void | - | Callback when the select open state changes |
isDisabled | boolean | false | Whether the select is disabled |
presentation | 'popover' | 'bottom-sheet' | 'dialog' | 'popover' | Presentation mode for the select content |
animation | SelectRootAnimation | - | Animation configuration |
asChild | boolean | false | Whether to render as a child element |
...ViewProps | ViewProps | - | All standard React Native View props are supported |
SelectRootAnimation
Animation configuration for Select component. Can be:
falseor"disabled": Disable only root animations"disable-all": Disable all animations including childrentrueorundefined: Use default animationsobject: Custom animation configuration
| prop | type | default | description |
|---|---|---|---|
state | 'disabled' | 'disable-all' | boolean | - | Disable animations while customizing properties |
entering.value | SpringAnimationConfig | TimingAnimationConfig | - | Animation configuration for when select opens |
exiting.value | SpringAnimationConfig | TimingAnimationConfig | - | Animation configuration for when select closes |
SpringAnimationConfig
| prop | type | default | description |
|---|---|---|---|
type | 'spring' | - | Animation type (must be 'spring') |
config | WithSpringConfig | - | Reanimated spring animation configuration |
TimingAnimationConfig
| prop | type | default | description |
|---|---|---|---|
type | 'timing' | - | Animation type (must be 'timing') |
config | WithTimingConfig | - | Reanimated timing animation configuration |
Select.Trigger
| prop | type | default | description |
|---|---|---|---|
variant | 'default' | 'unstyled' | 'default' | The variant of the trigger. 'default' applies pre-styled container styles, 'unstyled' removes default styling |
children | ReactNode | - | The trigger element content |
className | string | - | Additional CSS classes for the trigger |
asChild | boolean | true | Whether to render as a child element |
isDisabled | boolean | - | Whether the trigger is disabled |
...PressableProps | PressableProps | - | All standard React Native Pressable props are supported |
Select.Value
| prop | type | default | description |
|---|---|---|---|
placeholder | string | - | Placeholder text when no value is selected |
className | string | - | Additional CSS classes for the value |
...TextProps | TextProps | - | All standard React Native Text props are supported |
Note: The value component automatically applies different text colors based on selection state:
- When a value is selected:
text-foreground - When no value is selected (placeholder):
text-field-placeholder
Select.TriggerIndicator
| prop | type | default | description |
|---|---|---|---|
children | ReactNode | - | Custom indicator content. Defaults to animated chevron icon |
className | string | - | Additional CSS classes for the trigger indicator |
style | ViewStyle | - | Custom styles for the trigger indicator |
iconProps | SelectTriggerIndicatorIconProps | - | Chevron icon configuration |
animation | SelectTriggerIndicatorAnimation | - | Animation configuration |
isAnimatedStyleActive | boolean | true | Whether animated styles (react-native-reanimated) are active |
...ViewProps | ViewProps | - | All standard React Native View props are supported |
Note: The following style properties are occupied by animations and cannot be set via className:
transform(specificallyrotate) - Animated for open/close rotation transitions
To customize this property, use the animation prop. To completely disable animated styles and use your own via className or style prop, set isAnimatedStyleActive={false}.
SelectTriggerIndicatorIconProps
| prop | type | default | description |
|---|---|---|---|
size | number | 16 | Size of the icon |
color | string | - | Color of the icon (defaults to foreground theme color) |
SelectTriggerIndicatorAnimation
Animation configuration for Select.TriggerIndicator component. Can be:
falseor"disabled": Disable all animationstrueorundefined: Use default animations (rotation from 0° to -180°)object: Custom animation configuration
| prop | type | default | description |
|---|---|---|---|
state | 'disabled' | boolean | - | Disable animations while customizing properties |
rotation.value | [number, number] | [0, -180] | Rotation values [closed, open] in degrees |
rotation.springConfig | WithSpringConfig | { damping: 140, stiffness: 1000, mass: 4 } | Spring animation configuration for rotation |
Select.Portal
| prop | type | default | description |
|---|---|---|---|
children | ReactNode | - | The portal content (required) |
disableFullWindowOverlay | boolean | false | When true on iOS, uses View instead of FullWindowOverlay. Enables element inspector; overlay won't appear above native modals |
className | string | - | Additional CSS classes for the portal container |
hostName | string | - | Optional name of the host element for the portal |
forceMount | boolean | - | Whether to force mount the component in the DOM |
...ViewProps | ViewProps | - | All standard React Native View props are supported |
Select.Overlay
| prop | type | default | description |
|---|---|---|---|
className | string | - | Additional CSS classes for the overlay |
animation | SelectOverlayAnimation | - | Animation configuration |
isAnimatedStyleActive | boolean | true | Whether animated styles (react-native-reanimated) are active |
closeOnPress | boolean | true | Whether to close the select when overlay is pressed |
forceMount | boolean | - | Whether to force mount the component in the DOM |
asChild | boolean | false | Whether to render as a child element |
...Animated.ViewProps | Animated.ViewProps | - | All Reanimated Animated.View props are supported |
SelectOverlayAnimation
Animation configuration for Select.Overlay component. Can be:
falseor"disabled": Disable all animationstrueorundefined: Use default animations (progress-based opacity for bottom-sheet/dialog, Keyframe animations for popover)object: Custom animation configuration
| prop | type | default | description |
|---|---|---|---|
state | 'disabled' | boolean | - | Disable animations while customizing properties |
opacity.value | [number, number, number] | [0, 1, 0] | Opacity values [idle, open, close] (for bottom-sheet/dialog presentation) |
entering | EntryOrExitLayoutType | - | Custom Keyframe animation for entering transition (for popover presentation) |
exiting | EntryOrExitLayoutType | - | Custom Keyframe animation for exiting transition (for popover presentation) |
Select.Content (Popover Presentation)
| prop | type | default | description |
|---|---|---|---|
children | ReactNode | - | The select content |
width | number | 'trigger' | 'content-fit' | 'full' | 'content-fit' | Width sizing strategy for the content |
presentation | 'popover' | 'popover' | Presentation mode for the select |
placement | 'top' | 'bottom' | 'left' | 'right' | 'bottom' | Placement of the content relative to trigger |
align | 'start' | 'center' | 'end' | 'center' | Alignment along the placement axis |
avoidCollisions | boolean | true | Whether to flip placement when close to viewport edges |
offset | number | 8 | Distance from trigger element in pixels |
alignOffset | number | 0 | Offset along the alignment axis in pixels |
className | string | - | Additional CSS classes for the content container |
animation | SelectContentPopoverAnimation | - | Animation configuration |
forceMount | boolean | - | Whether to force mount the component in the DOM |
insets | Insets | - | Screen edge insets to respect when positioning |
asChild | boolean | false | Whether to render as a child element |
...Animated.ViewProps | Animated.ViewProps | - | All Reanimated Animated.View props are supported |
SelectContentPopoverAnimation
Animation configuration for Select.Content component (popover presentation). Can be:
falseor"disabled": Disable all animationstrueorundefined: Use default Keyframe animations (translateY/translateX, scale, opacity based on placement)object: Custom animation configuration withenteringand/orexitingKeyframe animations
| prop | type | default | description |
|---|---|---|---|
state | 'disabled' | boolean | - | Disable animations while customizing properties |
entering | EntryOrExitLayoutType | - | Custom Keyframe animation for entering transition (default: Keyframe with translateY/translateX, scale, opacity based on placement, 200ms) |
exiting | EntryOrExitLayoutType | - | Custom Keyframe animation for exiting transition (default: Keyframe mirroring entering animation, 150ms) |
Select.Content (Bottom Sheet Presentation)
| prop | type | default | description |
|---|---|---|---|
children | ReactNode | - | The bottom sheet content |
presentation | 'bottom-sheet' | - | Presentation mode for the select |
contentContainerClassName | string | - | Additional CSS classes for the content container |
...BottomSheetProps | BottomSheetProps | - | All @gorhom/bottom-sheet props are supported |
Select.Content (Dialog Presentation)
| prop | type | default | description |
|---|---|---|---|
children | ReactNode | - | The dialog content |
presentation | 'dialog' | - | Presentation mode for the select |
classNames | { wrapper?: string; content?: string } | - | Additional CSS classes for wrapper and content |
styles | Partial<Record<DialogContentFallbackSlots, ViewStyle>> | - | Styles for different parts of the dialog content |
animation | SelectContentAnimation | - | Animation configuration |
isSwipeable | boolean | true | Whether the dialog content can be swiped to dismiss |
forceMount | boolean | - | Whether to force mount the component in the DOM |
asChild | boolean | false | Whether to render as a child element |
...ViewProps | ViewProps | - | All standard React Native View props are supported |
styles
| prop | type | description |
|---|---|---|
wrapper | ViewStyle | Styles for the wrapper container |
content | ViewStyle | Styles for the dialog content |
SelectContentAnimation
Animation configuration for Select.Content component (dialog presentation). Can be:
falseor"disabled": Disable all animationstrueorundefined: Use default Keyframe animations (scale and opacity transitions)object: Custom animation configuration withenteringand/orexitingKeyframe animations
| prop | type | default | description |
|---|---|---|---|
state | 'disabled' | boolean | - | Disable animations while customizing properties |
entering | EntryOrExitLayoutType | - | Custom Keyframe animation for entering transition (default: Keyframe with scale and opacity, 200ms) |
exiting | EntryOrExitLayoutType | - | Custom Keyframe animation for exiting transition (default: Keyframe mirroring entering animation, 150ms) |
Select.Close
Select.Close extends CloseButton and automatically handles select dismissal when pressed.
Select.ListLabel
| prop | type | default | description |
|---|---|---|---|
children | ReactNode | - | The label text content |
className | string | - | Additional CSS classes for the list label |
...TextProps | TextProps | - | All standard React Native Text props are supported |
Select.Item
| prop | type | default | description |
|---|---|---|---|
children | ReactNode | ((props: SelectItemRenderProps) => ReactNode) | - | Custom item content. Defaults to label and indicator, or a render function |
value | any | - | The value associated with this item (required) |
label | string | - | The label text for this item (required) |
isDisabled | boolean | false | Whether this item is disabled |
className | string | - | Additional CSS classes for the item |
...PressableProps | PressableProps | - | All standard React Native Pressable props are supported |
SelectItemRenderProps
When using a render function for children, the following props are provided:
| property | type | description |
|---|---|---|
isSelected | boolean | Whether this item is currently selected |
value | string | The value of the item |
isDisabled | boolean | Whether the item is disabled |
Select.ItemLabel
| prop | type | default | description |
|---|---|---|---|
className | string | - | Additional CSS classes for the item label |
...TextProps | TextProps | - | All standard React Native Text props are supported |
Select.ItemDescription
| prop | type | default | description |
|---|---|---|---|
children | ReactNode | - | The description text content |
className | string | - | Additional CSS classes for the item description |
...TextProps | TextProps | - | All standard React Native Text props are supported |
Select.ItemIndicator
| prop | type | default | description |
|---|---|---|---|
children | ReactNode | - | Custom indicator content. Defaults to check icon |
className | string | - | Additional CSS classes for the item indicator |
iconProps | SelectItemIndicatorIconProps | - | Check icon configuration |
...ViewProps | ViewProps | - | All standard React Native View props are supported |
SelectItemIndicatorIconProps
| prop | type | default | description |
|---|---|---|---|
size | number | 16 | Size of the icon |
color | string | --colors-muted | Color of the icon |
Hooks
useSelect
Hook to access the Select root context. Returns the select state and control functions.
import { useSelect } from 'heroui-native';
const {
isOpen,
onOpenChange,
isDefaultOpen,
isDisabled,
presentation,
triggerPosition,
setTriggerPosition,
contentLayout,
setContentLayout,
nativeID,
value,
onValueChange,
} = useSelect();Return Value
| property | type | description |
|---|---|---|
isOpen | boolean | Whether the select is currently open |
onOpenChange | (open: boolean) => void | Callback to change the open state |
isDefaultOpen | boolean | undefined | Whether the select is open by default (uncontrolled mode) |
isDisabled | boolean | undefined | Whether the select is disabled |
presentation | 'popover' | 'bottom-sheet' | 'dialog' | Presentation mode for the select content |
triggerPosition | LayoutPosition | null | Position of the trigger element relative to viewport |
setTriggerPosition | (position: LayoutPosition | null) => void | Updates the trigger element's position |
contentLayout | LayoutRectangle | null | Layout measurements of the select content |
setContentLayout | (layout: LayoutRectangle | null) => void | Updates the content layout measurements |
nativeID | string | Unique identifier for the select instance |
value | SelectOption | Currently selected option |
onValueChange | (option: SelectOption) => void | Callback fired when the selected value changes |
Note: This hook must be used within a Select component. It will throw an error if called outside of the select context.
useSelectAnimation
Hook to access the Select animation state values within custom components or compound components.
import { useSelectAnimation } from 'heroui-native';
const { selectState, progress, isDragging, isGestureReleaseAnimationRunning } =
useSelectAnimation();Return Value
| property | type | description |
|---|---|---|
progress | SharedValue<number> | Progress value for animations (0=idle, 1=open, 2=close) |
isDragging | SharedValue<boolean> | Whether the select content is currently being dragged |
isGestureReleaseAnimationRunning | SharedValue<boolean> | Whether the gesture release animation is currently running |
Note: This hook must be used within a Select component. It will throw an error if called outside of the select animation context.
SelectOption
| property | type | description |
|---|---|---|
value | string | The value of the option |
label | string | The label text of the option |
useSelectItem
Hook to access the Select Item context. Returns the item's value and label.
import { useSelectItem } from 'heroui-native';
const { itemValue, label } = useSelectItem();Return Value
| property | type | description |
|---|---|---|
itemValue | string | The value of the current item |
label | string | The label text of the current item |
Special Notes
Element Inspector (iOS)
Select uses FullWindowOverlay on iOS. To enable the React Native element inspector during development, set disableFullWindowOverlay={true} on Select.Portal. Tradeoff: the select dropdown will not appear above native modals when disabled.