mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-28 07:09:50 +00:00
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.
389 lines
11 KiB
Plaintext
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>
|
|
)
|
|
```
|