Skip to content

Select

Persistent single string-value selection with anchored option surface and listbox semantics on Web.

import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from '@beemvp/beeui-ui';

There is no documented deep/private source import. For source ownership from a BeeUI checkout:

Terminal window
pnpm beeui -- add select

Registry metadata: registry/registry.json.

  • Family exports: Select SelectContent SelectGroup SelectItem SelectLabel SelectTrigger SelectValue

Exported types: SelectAlign, SelectCollisionPadding, SelectContentProps, SelectDirection, SelectGroupProps, SelectItemProps, SelectLabelProps, SelectOptionValue, SelectPlacement, SelectProps, SelectTriggerProps, SelectValueProps

The generated API inventory is mechanically joined to packages/ui/src/index.ts, Registry metadata, and the component reference contract. For behavior details and defaults, use the canonical component behavior catalog rather than copying TypeScript declarations into a second hand-maintained table.

Controlled/uncontrolled props, callbacks, disabled semantics, normalization/fail-safe behavior, and mount/unmount rules are defined by the public types and the canonical behavior catalog. The executable fixtures below are the source-grounded usage examples; consumers should not infer state ownership from DOM structure or another UI library.

  • BeeUIProvider is required above this family because it participates in shared overlay/toast runtime infrastructure.
  • Peer/native dependencies visible to this Registry item: react, react-native
  • Registry dependency closure: core-overlay, overlay-runtime, text, theme, use-direction
  • Safe-area ownership remains explicit: shell surfaces touching system edges opt into SafeArea; components do not silently invent app-shell insets.
  • Web consumers load the BeeUI semantic theme CSS as documented in Web onboarding.

The same public family is exposed across the supported target matrix; meaningful platform differences remain governed by the compatibility contract.

  • Web: live browser/keyboard behavior is verified by Web-specific checks where applicable.
  • iOS / Android: package/export/native compile evidence is not described as device-runtime proof. Consult the compatibility and native-preview guides for the exact evidence class.
  • Platform-specific or experimental behavior is called out in the canonical component/compatibility docs rather than hidden behind a generic parity claim.

Use the Accessibility overview, RTL/localization, and Large text & zoom alongside this family. Roles/states, keyboard/focus behavior, announcements, Dynamic Type/Web zoom, RTL, and reduced-motion expectations remain component-specific; BeeUI does not claim universal accessibility certification from automated tests.

BeeUI components consume semantic tokens and support the current typed variant/density contracts. Use Theming and Density. className is an implementation escape hatch for source-owned/application work, not a cross-engine portability guarantee.

Open the matching Web runtime in Showcase. The Showcase link demonstrates Web behavior; use the native-preview guide for real simulator/emulator/device paths.

This frame loads the real BeeUI Web Showcase on demand; it is not a second docs-only implementation. It proves browser behavior only. Use native preview for iOS/Android simulator, emulator or device paths.

  • Family root / primary export: Select
    • Public composition parts / helpers:
      • SelectContent
      • SelectGroup
      • SelectItem
      • SelectLabel
      • SelectTrigger
      • SelectValue
    • Exported type surface:
      • SelectAlign
      • SelectCollisionPadding
      • SelectContentProps
      • SelectDirection
      • SelectGroupProps
      • SelectItemProps
      • SelectLabelProps
      • SelectOptionValue
      • SelectPlacement
      • SelectProps
      • SelectTriggerProps
      • SelectValueProps

The tree above is ordinary document structure so it remains readable with keyboard and assistive technology; it is derived from the real public export family rather than a canvas-only diagram.

The following is the exact typechecked runtime Showcase fixture selected for this live preview: apps/showcase/component-gallery/select-showcase.tsx. Runtime gallery/pattern sources are preferred over test harnesses, and the displayed source and executable source are the same file; there is no separately maintained demo snippet.

import {
Box,
Button,
Card,
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogTitle,
DialogTrigger,
HStack,
Section,
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
Separator,
Text,
VStack,
} from '@beemvp/beeui-ui';
import * as React from 'react';
const SelectConsumerContext = React.createContext('select-context-default');
function SelectContextProbe({ testID }: { testID: string }) {
return <Text testID={testID}>{`context: ${React.useContext(SelectConsumerContext)}`}</Text>;
}
const LONG_OPTIONS = Array.from({ length: 120 }, (_, index) => ({
label: `Workspace ${String(index + 1).padStart(3, '0')}`,
value: `workspace-${index + 1}`,
}));
function SelectDismissHierarchyProbe() {
const [dialogOpen, setDialogOpen] = React.useState(false);
const [dialogSelectOpen, setDialogSelectOpen] = React.useState(false);
const [rootSelectOpen, setRootSelectOpen] = React.useState(false);
return (
<VStack gap="sm">
<Button
onPress={() => {
setRootSelectOpen(true);
setDialogOpen(true);
setDialogSelectOpen(true);
}}
testID="select-showcase-scope-open"
variant="outline"
>
Open dismissal hierarchy
</Button>
<Select onOpenChange={setRootSelectOpen} open={rootSelectOpen}>
<SelectTrigger testID="select-showcase-scope-root-trigger">
<SelectValue placeholder="Root Select" />
</SelectTrigger>
<SelectContent testID="select-showcase-scope-root-content">
<SelectItem value="root">Root option</SelectItem>
</SelectContent>
</Select>
<Dialog onOpenChange={setDialogOpen} open={dialogOpen}>
<DialogTrigger testID="select-showcase-scope-dialog-trigger">Scope Dialog</DialogTrigger>
<DialogContent>
<DialogTitle testID="select-showcase-scope-dialog-title">Dismiss hierarchy</DialogTitle>
<DialogDescription>
Escape must dismiss this modal-local Select before a root Select behind the Dialog.
</DialogDescription>
<Select onOpenChange={setDialogSelectOpen} open={dialogSelectOpen}>
<SelectTrigger testID="select-showcase-scope-child-trigger">
<SelectValue placeholder="Dialog Select" />
</SelectTrigger>
<SelectContent testID="select-showcase-scope-child-content">
<SelectItem value="child">Dialog option</SelectItem>
</SelectContent>
</Select>
<DialogFooter>
<DialogClose variant="outline">Close Dialog</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
</VStack>
);
}
export function SelectShowcase() {
const [controlledValue, setControlledValue] = React.useState('pro');
return (
<SelectConsumerContext.Provider value="preserved">
<VStack gap="lg">
<Card className="gap-5" variant="raised">
<Section
description="Select owns persistent option/value semantics. It reuses the anchored overlay runtime but not DropdownMenu command semantics."
title="Production Select"
>
<VStack gap="lg">
<VStack gap="xs">
<Text variant="label">Controlled value</Text>
<Select onValueChange={setControlledValue} value={controlledValue}>
<SelectTrigger
accessibilityLabel="Account plan"
testID="select-showcase-controlled-trigger"
>
<SelectValue
placeholder="Choose a plan"
testID="select-showcase-controlled-value"
/>
</SelectTrigger>
<SelectContent testID="select-showcase-controlled-content">
<SelectGroup>
<SelectLabel>Plans</SelectLabel>
<SelectItem testID="select-showcase-controlled-starter" value="starter">
Starter
</SelectItem>
<SelectItem testID="select-showcase-controlled-pro" value="pro">
Pro
</SelectItem>
<SelectItem disabled value="enterprise">
Enterprise — invite only
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<Text testID="select-showcase-controlled-state" tone="muted" variant="caption">
{`value: ${controlledValue}`}
</Text>
</VStack>
<Separator />
<HStack gap="lg" wrap>
<VStack className="min-w-52 flex-1" gap="xs">
<Text variant="label">Placeholder / uncontrolled</Text>
<Select>
<SelectTrigger
accessibilityLabel="Project role"
testID="select-showcase-placeholder-trigger"
>
<SelectValue
placeholder="Choose a role"
testID="select-showcase-placeholder-value"
/>
</SelectTrigger>
<SelectContent testID="select-showcase-placeholder-content">
<SelectItem testID="select-showcase-placeholder-designer" value="designer">
Designer
</SelectItem>
<SelectItem testID="select-showcase-placeholder-engineer" value="engineer">
Engineer
</SelectItem>
<SelectItem value="product">Product</SelectItem>
</SelectContent>
</Select>
</VStack>
<VStack className="min-w-52 flex-1" gap="xs">
<Text variant="label">Disabled Select</Text>
<Select disabled defaultValue="locked">
<SelectTrigger testID="select-showcase-disabled-trigger">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="locked">Managed by organization</SelectItem>
</SelectContent>
</Select>
</VStack>
</HStack>
<Separator />
<VStack gap="xs">
<Text variant="label">Grouped options</Text>
<Select defaultValue="tokyo">
<SelectTrigger accessibilityLabel="Office" testID="select-showcase-group-trigger">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Asia Pacific</SelectLabel>
<SelectItem value="tokyo">Tokyo</SelectItem>
<SelectItem value="singapore">Singapore</SelectItem>
<SelectItem value="sydney">Sydney</SelectItem>
</SelectGroup>
<SelectGroup>
<SelectLabel>Europe</SelectLabel>
<SelectItem value="paris">Paris</SelectItem>
<SelectItem value="london">London</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</VStack>
<Separator />
<VStack gap="xs">
<Text variant="label">Consumer context through root portal</Text>
<Select defaultValue="context">
<SelectTrigger testID="select-showcase-context-trigger">
<SelectValue testID="select-showcase-context-value" />
</SelectTrigger>
<SelectContent testID="select-showcase-context-content">
<SelectItem textValue="Context-aware option" value="context">
<SelectContextProbe testID="select-showcase-context-probe" />
</SelectItem>
<SelectItem value="plain">Plain option</SelectItem>
</SelectContent>
</Select>
</VStack>
</VStack>
</Section>
</Card>
<Card className="gap-5">
<Section
description="The list stays a ScrollView in v1. A 120-option fixture validates viewport max-height, collision, selected-item scrolling, and ordinary press/keyboard selection without adding virtualization."
title="Long list"
>
<Select defaultValue="workspace-118">
<SelectTrigger accessibilityLabel="Workspace" testID="select-showcase-long-trigger">
<SelectValue testID="select-showcase-long-value" />
</SelectTrigger>
<SelectContent maxHeight={220} testID="select-showcase-long-content">
{LONG_OPTIONS.map((option, index) => (
<SelectItem
key={option.value}
testID={
index === 0
? 'select-showcase-long-first'
: index === LONG_OPTIONS.length - 1
? 'select-showcase-long-last'
: undefined
}
value={option.value}
>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
</Section>
</Card>
<Card className="gap-5">
<Section
description="The same selection API is rendered in a deliberately narrow container and inside Dialog's modal-local overlay host."
title="Narrow viewport and Dialog nesting"
>
<VStack gap="lg">
<Box className="w-full max-w-64" testID="select-showcase-narrow-shell">
<Select defaultValue="very-long-option">
<SelectTrigger accessibilityLabel="Narrow Select" testID="select-showcase-narrow-trigger">
<SelectValue />
</SelectTrigger>
<SelectContent testID="select-showcase-narrow-content">
<SelectItem value="short">Short option</SelectItem>
<SelectItem value="very-long-option">
A long option label that must truncate safely in a narrow layout
</SelectItem>
</SelectContent>
</Select>
</Box>
<Dialog>
<DialogTrigger testID="select-showcase-dialog-trigger" variant="outline">
Select inside Dialog
</DialogTrigger>
<DialogContent>
<DialogTitle>Assign owner</DialogTitle>
<DialogDescription>
Select content resolves against this Dialog's modal-local host while preserving consumer context.
</DialogDescription>
<Select defaultValue="context-user">
<SelectTrigger
accessibilityLabel="Owner"
testID="select-showcase-dialog-select-trigger"
>
<SelectValue testID="select-showcase-dialog-select-value" />
</SelectTrigger>
<SelectContent testID="select-showcase-dialog-select-content">
<SelectItem textValue="Context user" value="context-user">
<SelectContextProbe testID="select-showcase-dialog-context-probe" />
</SelectItem>
<SelectItem
testID="select-showcase-dialog-alex"
value="alex"
>
Alex Morgan
</SelectItem>
</SelectContent>
</Select>
<DialogFooter>
<DialogClose variant="outline">Done</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
<Separator />
<SelectDismissHierarchyProbe />
</VStack>
</Section>
</Card>
</VStack>
</SelectConsumerContext.Provider>
);
}

Use the code block’s copy affordance to copy the exact fixture. For a smaller app-specific example, start from the public imports shown above and keep only the state your screen owns.

No component-specific limitation is curated here. Check Compatibility and the linked behavior contract for target-specific constraints.