Files
docs/apps/gui-docs/content/docs/components/select.mdx
zeekay a572ed7c00 feat: add gui-docs app for gui.hanzo.ai
Migrated 93 MDX pages from old Tamagui-based site to @hanzo/docs system:
- 13 intro pages (installation, props, styles, themes, etc.)
- 22 core pages (configuration, styled, variants, animations, etc.)
- 48 component pages (button, dialog, select, toast, etc.)
- 14 guide pages (next-js, expo, vite, webpack, metro, etc.)

Zero tamagui references. Uses @hanzo/docs-base-ui + @hanzo/docs-mdx.
2026-03-29 16:47:38 -07:00

389 lines
11 KiB
Plaintext

---
title: Select
description: Show a menu of items that users can select from
name: select
component: Select
package: select
demoName: Select
---
- Comes with styling, yet completely customizable and themeable.
- Accepts animations, themes, size props and more.
- Accessible, keyboard navigable, full-featured.
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](/ui/z-index) above other content.
## Installation
Select is already installed in `@hanzo/gui`, or you can install it independently:
```bash
npm install @hanzogui/select
```
<Notice theme="blue">
For native apps, we recommend [setting up native
portals](/docs/components/portal#native-portal-setup-recommended) to preserve React
context inside Select content.
</Notice>
## Anatomy
```tsx
import { Select } from '@hanzo/gui' // or '@hanzogui/select'
export default () => (
<Select defaultValue="">
<Select.Trigger>
<Select.Value placeholder="Search..." />
</Select.Trigger>
{/* Optional: Control focus behavior */}
<Select.FocusScope loop trapped focusOnIdle={true}>
<Select.Content>
<Select.ScrollUpButton />
<Select.Viewport>
<Select.Group>
<Select.Label />
<Select.Item>
<Select.ItemText />
</Select.Item>
</Select.Group>
</Select.Viewport>
<Select.ScrollDownButton />
</Select.Content>
</Select.FocusScope>
</Select>
)
```
<Notice>
Note that Select only works on Native using the Adapt component to adapt it to a Sheet.
See below for docs.
</Notice>
## API Reference
### Select
Contains every component for the select:
<PropsTable
data={[
{
name: 'id',
type: 'string',
description: `Optional for usage with Label.`,
},
{
name: 'size',
type: 'SizeTokens',
description: `Set the size of itself and pass to all inner elements.`,
},
{
name: 'children',
type: 'React.ReactNode',
description: `Select children API components.`,
},
{
name: 'value',
type: 'string',
description: `Controlled value.`,
},
{
name: 'defaultValue',
type: 'string',
description: `Default value.`,
},
{
name: 'onValueChange',
type: '(value: string) => void',
description: `Callback on value change.`,
},
{
name: 'open',
type: 'boolean',
description: `Controlled open value.`,
},
{
name: 'defaultOpen',
type: 'boolean',
description: `Default open value.`,
},
{
name: 'onOpenChange',
type: '(open: boolean) => void',
description: `Callback on open change.`,
},
{
name: 'dir',
type: 'Direction',
description: `Direction of text display.`,
},
{
name: 'name',
type: 'string',
description: `For use in forms.`,
},
{
name: 'native',
type: 'NativeValue',
description: `If passed, will render a native component instead of the custom one. Currently only \`web\` is supported.`,
},
{
name: 'renderValue',
type: '(value: string) => ReactNode',
description: `Render function for the selected value. Useful for SSR when you need custom display text. By default, Select falls back to showing the raw value for SSR compatibility.`,
},
{
name: 'lazyMount',
type: 'boolean',
default: 'false',
description: `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.`,
},
{
name: 'zIndex',
type: 'number',
description: `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).`,
},
]}
/>
### Select.Trigger
Extends [ListItem](/docs/components/list-item) to give sizing, icons, and more.
### Select.Value
Extends [Paragraph](/docs/components/text), adding:
<PropsTable
data={[
{
name: 'placeholder',
type: 'string',
description: `Optional placeholder to show when no value selected.`,
},
]}
/>
### Select.Content
Main container for Select content, used to contain the up/down arrows, no API beyond children.
### Select.ScrollUpButton
Inside Content first, displays when you can scroll up, stuck to the top.
Extends [YStack](/docs/components/stacks).
### Select.ScrollDownButton
Inside Content last, displays when you can scroll down, stuck to the bottom.
Extends [YStack](/docs/components/stacks).
### Select.Viewport
Extends [ThemeableStack](/docs/components/stacks#themeablestack). Contains scrollable content items as children.
<PropsTable
data={[
{
name: 'disableScroll',
type: 'boolean',
description: `Removes ability to scroll and all style and functionality related to scrolling.`,
},
{
name: 'unstyled',
type: 'boolean',
description: `Removes all default styles.`,
},
]}
/>
<Notice>
Make sure to not pass `height` prop as that is managed internally because of UX reasons
and having a fixed height will break that behavior.
</Notice>
### Select.Group
Extends [YStack](/docs/components/stacks). Use only when grouping together items, alongside a Label as the first child.
### Select.Label
Extends [SizableText](/docs/components/text). Used to label Groups. Includes size-based padding and minHeight for consistent appearance with other Select items.
### Select.Item
Extends [ListItem](/docs/components/list-item). Used to add selectable values to the list. Must provide an index as React Native doesn't give any escape hatch for us to configure that automatically.
<PropsTable
data={[
{
name: 'index',
type: 'number',
required: true,
description: `Incrementally starting from 0, matching its appearance in the list.`,
},
{
name: 'value',
type: 'string',
description: `Provide a value that will be passed on selection.`,
},
]}
/>
### Select.ItemText
Extends [Paragraph](/docs/components/text). Used inside Item to provide unselectable text that will show above once selected in the parent Select.
### Select.Indicator
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.
```tsx
<Select.Viewport>
<Select.Indicator transition="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`.
<Notice>
By default, Select uses the item's `hoverStyle` and `pressStyle` 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.
</Notice>
### Select.FocusScope
Provides access to the underlying FocusScope component used by Select for focus management. Can be used to control focus behavior from a parent component.
<PropsTable
data={[
{
name: 'enabled',
type: 'boolean',
default: 'true',
description: `Whether focus management is enabled.`,
},
{
name: 'loop',
type: 'boolean',
default: 'false',
description: `When true, tabbing from last item will focus first tabbable and shift+tab from first item will focus last tabbable.`,
},
{
name: 'trapped',
type: 'boolean',
default: 'false',
description: `When true, focus cannot escape the focus scope via keyboard, pointer, or programmatic focus.`,
},
{
name: 'focusOnIdle',
type: 'boolean | number',
default: 'false',
description: `When true, waits for idle before focusing. When a number, waits that many ms. This prevents reflows during animations.`,
},
{
name: 'onMountAutoFocus',
type: '(event: Event) => void',
description: `Event handler called when auto-focusing on mount. Can be prevented.`,
},
{
name: 'onUnmountAutoFocus',
type: '(event: Event) => void',
description: `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`:
```tsx
const labels = {
apple: 'Apple',
orange: 'Orange',
banana: 'Banana',
}
<Select
lazyMount
renderValue={(value) => labels[value]}
defaultValue="apple"
>
{/* 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.Item index={0} value="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.
### Select.Sheet
When used alongside `<Adapt />`, Select will render as a sheet when that breakpoint is active.
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 Hanzo GUI wants to present the right abstractions for each platform.
See [Sheet](/docs/components/sheet) for more props.
Must use `Select.Adapt.Contents` inside the `Select.Sheet.Frame` to insert the contents given to `Select.Content`
```tsx
import { Select } from '@hanzo/gui' // or '@hanzogui/select'
export default () => (
<Select defaultValue="">
<Select.Trigger>
<Select.Value placeholder="Search..." />
</Select.Trigger>
<Adapt when="max-md" platform="touch">
{/* or <Select.Sheet> */}
<Sheet>
<Sheet.Frame>
<Adapt.Contents />
</Sheet.Frame>
<Sheet.Overlay />
</Sheet>
</Adapt>
<Select.Content>
<Select.ScrollUpButton />
<Select.Viewport>
<Select.Group>
<Select.Label />
<Select.Item>
<Select.ItemText />
</Select.Item>
</Select.Group>
</Select.Viewport>
<Select.ScrollDownButton />
</Select.Content>
</Select>
)
```