Select gives users an accessible, keyboard-navigable list of choices and can
adapt its content into a Sheet on smaller screens.
Features
Customizable, themeable default styling
Transitions, themes, and size props
Full-featured, accessible, and keyboard navigable
Shared Sheet handoff with Dialog and Popover
Select provides a dropdown menu for choosing from a list of options. It’s fully accessible with keyboard navigation, supports typeahead search, and automatically stacks above other content.
In v3, Select keeps adapted sheet content mounted through the sheet exit
animation, and web trigger and viewport parts expose data-state="open" | "closed"
for styling.
Select also supports ordered multiple selection across custom web lists,
browser-native controls, adapted Sheets, and plain React Native content. The
same item registry and value controller power every path.
Installation
Select is already installed in tamagui, or you can install it independently:
yarn
npm
bun
pnpm
yarn add @tamagui/select
For native apps, we recommend setting up native
portals to preserve React
context inside Select content.
Anatomy
// copy-paste: these skins import from files you own. copy each registry item
// below into your app, then adjust the relative import paths to fit.
Pass multiple to use a controlled or uncontrolled string[]. Selecting a new
item appends it. Selecting it again removes it without changing the order of the
remaining values. Multiple selection keeps custom lists and adapted Sheets open.
Select.Value renders registered Select.ItemText labels in selection order,
separated by , . Use renderValue for chips, localized separators, summaries,
or labels that must render before lazy items mount.
A custom floating web Select is an ARIA multi-select listbox. Arrow keys and
typeahead move focus. Enter and Space toggle the focused option.
native="web" renders a real <select multiple>. Browser selection,
keyboard behavior, and form submission are authoritative.
An adapted Sheet uses the same listbox controller on web and stays open after
each toggle. The Sheet closes through its overlay, drag-to-bottom behavior,
platform back action, or controlled state. Select does not add a Done row.
Plain React Native content renders inline when no Adapt target is active.
Multiple items expose checkbox-style accessibility state and remain visible
after a toggle.
On custom web paths, name renders one root-level hidden input per selected
value, including when the collection is portaled into a Sheet. form can point
those inputs at an external form. The browser-native path puts name and form
on its <select> directly and does not render hidden inputs. React Native does
not render HTML form controls.
Set the size of itself and pass to all inner elements.
children
React.ReactNode
Select children API components.
value
string | string[]
Controlled value. With multiple, this is an ordered string array.
defaultValue
string | string[]
Default value. With multiple, this defaults to an empty array.
multiple
boolean
Default:
false
Enables ordered multiple selection and makes value callbacks array-valued.
onValueChange
(value, details) => void
Cancelable value request. Details identify item-press, keyboard, or native-change.
open
boolean
Controlled open value.
defaultOpen
boolean
Default open value.
onOpenChange
(open: boolean, details) => void
Cancelable open request with the interaction reason and source event.
dir
Direction
Direction of text display.
name
string
Web form field name. Multiple values submit as repeated entries.
form
string
Associates the web form control with an external form id.
native
NativeValue
If passed, will render a native component instead of the custom one. Currently only `web` is supported.
renderValue
(value: string | string[]) => ReactNode
Render function for the selected value. Multiple mode receives the ordered string array. Useful for SSR, lazy mounting, chips, and custom summaries.
lazyMount
boolean
Default:
false
When true, defers mounting Select items until opened using React's startTransition. Significantly improves initial render performance for pages with many Selects. Should be combined with `renderValue` for best results.
zIndex
number
z-index for the select portal. Use when select dropdowns need to appear above other portaled content like dialogs or fixed headers. Defaults to automatic stacking (~100000).
Extends ListItem. Used to add selectable string values to the
list. Item registration order controls keyboard navigation, typeahead, and
selection anchoring.
An animated indicator that highlights the currently focused item. Place it inside Select.Viewport to enable a smooth sliding highlight animation as users navigate through options.
<Select.Viewport>
<Select.Indicatortransition="quick"/>
<Select.Group>{/* items */}</Select.Group>
</Select.Viewport>
Use the transition prop to control the animation speed. You can use any animation name from your config like quick, quicker, or quickest.
By default, Select uses the item’s hover: and press: clauses for hover feedback. Add
Select.Indicator for a smoother animated effect. If using the indicator, you may want
to set items to have transparent hover styles to avoid visual conflict.
Provides access to the underlying FocusScope component used by Select for focus management. Can be used to control focus behavior from a parent component.
Props
enabled
boolean
Default:
true
Whether focus management is enabled.
loop
boolean
Default:
false
When true, tabbing from last item will focus first tabbable and shift+tab from first item will focus last tabbable.
trapped
boolean
Default:
false
When true, focus cannot escape the focus scope via keyboard, pointer, or programmatic focus.
noFocus
boolean
Default:
false
Zero focus mode. While active, focus is allowed neither inside nor outside the scope. Web only.
focusOnIdle
boolean | number
Default:
true
When true, waits for idle before focusing. When a number, waits that many ms. This prevents reflows during animations.
onMountAutoFocus
(event: Event) => void
Event handler called when auto-focusing on mount. Can be prevented.
onUnmountAutoFocus
(event: Event) => void
Event handler called when auto-focusing on unmount. Can be prevented.
Performance
For pages with many Select components, you can significantly improve initial render performance by using the lazyMount prop combined with renderValue:
{/* Items are not mounted until the Select is opened */}
<Select.Trigger>
<Select.Value/>
</Select.Trigger>
<Select.Content>
<Select.Viewport>
{/* These items mount in a startTransition when first opened */}
<Select.Itemvalue="apple">
<Select.ItemText>Apple</Select.ItemText>
</Select.Item>
{/* ... more items */}
</Select.Viewport>
</Select.Content>
</Select>
How it works:
lazyMount defers mounting all Select items until the dropdown is first opened
The mount happens inside React’s startTransition, keeping the trigger responsive
renderValue provides the display text synchronously, avoiding the need to mount items just to show the selected value
Once mounted, items stay mounted for fast subsequent opens
This is especially useful when rendering many Selects on a single page, as each Select with 20+ items would otherwise mount all those items on initial page load.
When used alongside <Adapt />, Select will render as a sheet when that breakpoint is active. See Adapt for how the handoff works.
This is the only way to render a Select on Native for now, as mobile apps tend to show Select very differently from web and Tamagui wants to present the right abstractions for each platform.
v2-look Select: styled trigger/value/icon, viewport with shadow, items with highlight + check indicator, scroll buttons and separators, over the unstyled @tamagui/ui Select behavior. Adapts to a Sheet on native. This is the exact source the registry ships — copy it into your app and the examples above import from your copy.
Expects theme tokens: background, background-hover, background-press, background-focus, border-color, border-color-hover, outline-color, color, color-10. Native: requires a Portal/Adapt provider at the app root; on native the Select adapts to a Sheet, so the Sheet native peer requirements apply when adaptation is used
Need raw behavior without any skin? tamagui/unstyled re-exports the @tamagui/ui primitives (advanced).