suiss/uim · React Native Component

Select

A control that opens a floating list of options and shows the chosen one in its trigger.

Select is an open-source mobile component from suiss/uim for React Native and Expo, with SwiftUI and Jetpack Compose versions built from the same design tokens. The @esuiss/uim CLI copies its source into your project, so you own the code.

iOS
Select (open by default) on iOS in light mode

Select is built on the select primitive. SelectTrigger is a pressable field with the combobox role and an up-down caret. SelectContent renders in a portal, positioned next to the trigger, and fades in and out with Reanimated. The list matches the trigger width.

The trigger comes in two sizes, default and sm. Use Select for picking one value from a short list; for a list that needs searching, use Combobox.

Installation

$ pnpm dlx @esuiss/uim@latest add select

The CLI also adds what it builds on: Icon, Text.

Manual

  1. Install the dependencies:
npx expo install cn phosphor-react-native react-native-reanimated react-native-screens react-native-svg react-native-worklets
  1. Add the pieces it builds on: Icon, Text, and the primitives components/primitives/field.tsx, components/primitives/positioner.tsx, components/primitives/select.tsx, components/primitives/use-render.tsx.

  2. Copy the source into components/ui/select.tsx:

uniwind/components/ui/select.tsx
import { cn } from "cn"
import { CaretUpDownIcon, CheckIcon } from "phosphor-react-native"
import * as React from "react"
import { Platform, type StyleProp, type ViewStyle } from "react-native"
import { FadeIn, FadeOut, ReduceMotion } from "react-native-reanimated"
import { FullWindowOverlay as RNFullWindowOverlay } from "react-native-screens"
import { useFieldRootContext } from "@/components/primitives/field"
import { useOptionalPositionerContext } from "@/components/primitives/positioner"
import * as SelectPrimitive from "@/components/primitives/select"
import {
  resolveClassName,
  resolveStyle,
} from "@/components/primitives/use-render"
import { AnimatedView } from "@/components/ui/animated-view"
import { Icon } from "@/components/ui/icon"
import { TextClassContext } from "@/components/ui/text"
  1. Update the import paths to match your project.

Usage

import { SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator } from "@/components/ui/select"
<SelectDemo initial={fruits[2]} defaultOpen />

Put a SelectValue inside SelectTrigger, and SelectItem entries inside SelectContent. Group items with SelectGroup and SelectLabel, and divide groups with SelectSeparator.

Control the value with value and onValueChange on Select, or start from defaultValue. Pass the full option list as items so SelectValue can show the label of the current value. Select also accepts multiple, disabled, readOnly, open, defaultOpen and onOpenChange.

Give each SelectItem a value and a label; the label is shown when no children are passed. SelectValue shows placeholder until a value is chosen. The Option type ({ value, label }) is also exported.

Examples

Default

iOS
Select on iOS in light mode

With value

A select that starts with a chosen value.

iOS
Select (with value) on iOS in light mode

Small

The sm trigger size.

iOS
Select (small) on iOS in light mode

Grouped

Two labeled groups divided by a separator.

iOS
Select (grouped) on iOS in light mode

With label

A select labeled by a Label through accessibilityLabelledBy, with helper text.

iOS
Select (with label) on iOS in light mode

Disabled

A disabled select with a value.

iOS
Select (disabled) on iOS in light mode

Invalid

The invalid state with an error message.

iOS
Select (invalid) on iOS in light mode

API Reference

SelectGroup

Groups related items.

ExtendsReact.ComponentProps<typeof SelectPrimitive.Group>

SelectValue

Shows the selected label or the placeholder.

ExtendsReact.ComponentProps<typeof SelectPrimitive.Value>

SelectTrigger

Pressable field that opens the list.

ExtendsReact.ComponentProps<typeof SelectPrimitive.Trigger>
PropType
Type
React.ReactNode
Default
—
About
Trigger height: default or sm.
Type
"default""sm"
Default
"default"
About
Shows the danger border. Falls back to the invalid state of an enclosing field.
Type
boolean
Default
—

SelectContent

Floating list rendered in a portal.

ExtendsReact.ComponentProps<typeof SelectPrimitive.Popup>PositionerProps
PropType
About
Name of the portal host to render into.
Type
string
Default
—

SelectLabel

Heading for a group.

ExtendsReact.ComponentProps<typeof SelectPrimitive.GroupLabel>

SelectItem

One option, with a check mark when selected.

ExtendsReact.ComponentProps<typeof SelectPrimitive.Item>
PropType
Type
React.ReactNode
Default
—

SelectSeparator

Line between groups.

ExtendsReact.ComponentProps<typeof SelectPrimitive.Separator>

Accessibility

  • The trigger has the combobox role and reports its expanded and disabled states.
  • The list has the list role; each item has the option role, uses its label as accessibilityLabel and reports selected and disabled states.
  • Groups have the group role and are labeled by their SelectLabel.
  • Label the trigger with accessibilityLabelledBy pointing at a Label's nativeID, or with accessibilityLabel.
  • The Android back button and the VoiceOver escape gesture close the list.

Notes

  • Uses bg-control for the trigger, bg-surface-raised for the list and text-link for the check mark; colors follow the system appearance.
  • On iOS the list renders inside a FullWindowOverlay from react-native-screens, so it appears above native modals.