Preview Only: These components are for reference only. Continue using Orbiter in production until further notice.

Select

A select displays a collapsible list of options from which the user can select one.

import { Select, SelectItem } from "@hopper-ui/components"; export default function Example() { return ( <Select label="Roles"> <SelectItem id="designer">Designer</SelectItem> <SelectItem id="developer">Developer</SelectItem> <SelectItem id="manager">Manager</SelectItem> </Select> ); }

Anatomy

The Header component represents a header within a Hopper container.

Section

The Section component represents a section within a Hopper container.

Composed Components

A Select uses the following components:

Usage

Disabled

A select in a disabled state shows that it exists, but is not available in that circumstance. This can be used to maintain layout continuity and communicate that a field may become available later.

import { Select, SelectItem } from "@hopper-ui/components"; export default function Example() { return ( <Select isDisabled label="Roles" > <SelectItem id="designer">Designer</SelectItem> <SelectItem id="developer">Developer</SelectItem> <SelectItem id="manager">Manager</SelectItem> </Select> ); }

Disabled Item

A select with a disabled item.

import { Select, SelectItem } from "@hopper-ui/components"; export default function Example() { return ( <Select disabledKeys={["developer"]} aria-label="list of options" > <SelectItem id="designer">Designer</SelectItem> <SelectItem id="developer">Developer</SelectItem> <SelectItem id="manager">Manager</SelectItem> </Select> ); }

Error

A select can be displayed in an error state to indicate that the selection is invalid.

import { Select, SelectItem } from "@hopper-ui/components"; export default function Example() { return ( <Select isInvalid label="Roles" errorMessage="This field is required" > <SelectItem id="designer">Designer</SelectItem> <SelectItem id="developer">Developer</SelectItem> <SelectItem id="manager">Manager</SelectItem> </Select> ); }

Sizes

A select has multiple sizes to choose from. The select menu also changes size based on the size of the select.

import { Select, SelectItem, Stack } from "@hopper-ui/components"; export default function Example() { return ( <Stack> <Select label="Roles"> <SelectItem id="designer">Designer</SelectItem> <SelectItem id="developer">Developer</SelectItem> <SelectItem id="manager">Manager</SelectItem> </Select> <Select size="md" label="Roles"> <SelectItem id="designer">Designer</SelectItem> <SelectItem id="developer">Developer</SelectItem> <SelectItem id="manager">Manager</SelectItem> </Select> </Stack> ); }

Labeling

If a visible label isn't specified, an aria-label must be provided to the select for accessibility. If the field is labeled by a separate element, an aria-labelledby prop must be provided using the ID of the labeling element instead.

import { Select, SelectItem } from "@hopper-ui/components"; export default function Example() { return ( <Select aria-label="Roles"> <SelectItem id="designer">Designer</SelectItem> <SelectItem id="developer">Developer</SelectItem> <SelectItem id="manager">Manager</SelectItem> </Select> ); }

Icon Prefix

An icon can be displayed at the start of the select trigger.

import { Select, SelectItem } from "@hopper-ui/components"; import { OrgChartIcon } from "@hopper-ui/icons"; export default function Example() { return ( <Select prefix={<OrgChartIcon />} label="Roles" > <SelectItem id="designer">Designer</SelectItem> <SelectItem id="developer">Developer</SelectItem> <SelectItem id="manager">Manager</SelectItem> </Select> ); }

Text Prefix

A short text can be displayed at the start of the select trigger.

import { Select, SelectItem } from "@hopper-ui/components"; export default function Example() { return ( <Select prefix="Operations" label="Roles" > <SelectItem id="project-coordinator">Project Coordinator</SelectItem> <SelectItem id="qa-specialist">QA Specialist</SelectItem> <SelectItem id="system-administrator">System Administrator</SelectItem> </Select> ); }

Fluid

A select can take the width of its container.

import { Select, SelectItem } from "@hopper-ui/components"; export default function Example() { return ( <Select isFluid label="Roles" > <SelectItem id="designer">Designer</SelectItem> <SelectItem id="developer">Developer</SelectItem> <SelectItem id="manager">Manager</SelectItem> </Select> ); }

Custom Value

A select's trigger value can be customized using the renderValue function to allow other elements such as an avatar or icon inside the trigger value.

import { Avatar, Select, SelectItem, Text, type ValueRenderProps } from "@hopper-ui/components"; import { users, type User } from "./data.ts"; const renderValue = ({ defaultChildren, selectedItem }: ValueRenderProps<User>) => { if (selectedItem) { const { name, avatar } = selectedItem; return ( <> <Avatar name={name} src={avatar} /> <Text>{name}</Text> </> ); } return defaultChildren; }; export default function Example() { const [firstUser] = users; return ( <Select renderValue={renderValue} defaultSelectedKey={firstUser.id} items={users} label="Users" > {({ id, name, avatar, role }) => { return ( <SelectItem id={id} textValue={name}> <Avatar name={name} src={avatar} /> <Text>{name}</Text> <Text slot="description">{role}</Text> </SelectItem> ); }} </Select> ); }

Controlled

A select can have a controlled selected value. In this example, it shows how it is possible to deselect an option.

import { Header, Select, SelectItem, SelectSection, type Key } from "@hopper-ui/components"; import { useState } from "react"; export default function Example() { const [selectedKey, setSelectedKey] = useState<Key | null>(); const handleSelectionChange = (key: Key) => { if (selectedKey === key) { setSelectedKey(null); } else { setSelectedKey(key); } }; return ( <Select selectedKey={selectedKey} onSelectionChange={handleSelectionChange} label="Roles"> <SelectSection> <Header>Operations</Header> <SelectItem id="1">Project Coordinator</SelectItem> <SelectItem id="2">QA Specialist</SelectItem> </SelectSection> <SelectItem id="3">Manager</SelectItem> </Select> ); }

Form

A select can be part of a form. To submit the value of a select, make sure you specify the name property.

import { Form, Select, SelectItem } from "@hopper-ui/components"; export default function Example() { return ( <Form> <Select name="roles" label="Roles" > <SelectItem id="designer">Designer</SelectItem> <SelectItem id="developer">Developer</SelectItem> <SelectItem id="manager">Manager</SelectItem> </Select> </Form> ); }

Auto Menu Width

A select can have a menu that automatically adjusts its width based on the longest item.

import { Select, SelectItem, Text } from "@hopper-ui/components"; export default function Example() { return ( <Select aria-label="list of options with a description" isAutoMenuWidth > <SelectItem textValue="Designer"> <Text>Designer</Text> <Text slot="description">Builds and maintains software.</Text> </SelectItem> <SelectItem textValue="Developer"> <Text>Developer</Text> <Text slot="description">Creates visual design solutions.</Text> </SelectItem> <SelectItem textValue="Manager"> <Text>Manager</Text> <Text slot="description">Leads teams and projects.</Text> </SelectItem> </Select> ); }

Menu placement

A select's menu can have a customized menu placement using the direction and align props.

import { Select, SelectItem } from "@hopper-ui/components"; export default function Example() { return ( <Select aria-label="Roles" isAutoMenuWidth align="start" direction="top" > <SelectItem id="designer">Designer</SelectItem> <SelectItem id="developer">Developer</SelectItem> <SelectItem id="manager">Manager</SelectItem> </Select> ); }

Section

A select can have sections and section headers.

import { Header, Select, SelectItem, SelectSection } from "@hopper-ui/components"; export default function Example() { return ( <Select aria-label="list of options"> <SelectItem>Developer</SelectItem> <SelectItem>Manager</SelectItem> <SelectSection> <Header>Creative Department</Header> <SelectItem>Designer</SelectItem> <SelectItem>Copywriter</SelectItem> <SelectItem>UX Researcher</SelectItem> </SelectSection> <SelectSection> <Header>Operations</Header> <SelectItem>Project Coordinator</SelectItem> <SelectItem>QA Specialist</SelectItem> </SelectSection> <SelectItem>Product Owner</SelectItem> </Select> ); }

A select can have a footer.

import { Button, Select, SelectItem, Text } from "@hopper-ui/components"; import { AddIcon } from "@hopper-ui/icons"; export default function Example() { return ( <Select aria-label="list of options with a description" footer={<Button variant="ghost-secondary" isFluid><AddIcon /><Text>Add</Text></Button>} > <SelectItem textValue="Designer"> <Text>Designer</Text> <Text slot="description">Builds and maintains software.</Text> </SelectItem> <SelectItem textValue="Developer"> <Text>Developer</Text> <Text slot="description">Creates visual design solutions.</Text> </SelectItem> <SelectItem textValue="Manager"> <Text>Manager</Text> <Text slot="description">Leads teams and projects.</Text> </SelectItem> </Select> ); }

Avatar

A select option can contain an avatar.

import { Avatar, Select, SelectItem, Text } from "@hopper-ui/components"; export default function Example() { return ( <Select aria-label="Team"> <SelectItem textValue="Fred Smith"> <Avatar src="https://i.pravatar.cc/96?img=3" name="Fred Smith" /> <Text>Fred Smith</Text> </SelectItem> <SelectItem textValue="Karen Smith"> <Avatar name="Karen Smith" /> <Text>Karen Smith</Text> </SelectItem> <SelectItem textValue="John Doe"> <Avatar name="John Doe" /> <Text>John Doe</Text> </SelectItem> </Select> ); }

Count

A select option can contain a count using a badge.

import { Badge, Select, SelectItem, Text } from "@hopper-ui/components"; export default function Example() { return ( <Select aria-label="list of options"> <SelectItem textValue="Designer"> <Text>Designer</Text> <Badge>50</Badge> </SelectItem> <SelectItem textValue="Developer"> <Badge variant="secondary">99+</Badge> <Text>Developer</Text> </SelectItem> <SelectItem>Manager</SelectItem> </Select> ); }

Dynamic Lists

Options and sections can be populated from a hierarchial data structure. If a section has a header, the Collection component can be used to render the child items.

import { Collection, Header, Select, SelectItem, SelectSection } from "@hopper-ui/components"; const OPTIONS = [ { role: "Operations", children: [ { id: 2, role: "Project Coordinator" }, { id: 3, role: "QA Specialist" }, { id: 4, role: "System Administrator" } ] }, { role: "Creative Department", children: [ { id: 6, role: "Designer" }, { id: 7, role: "Designer" }, { id: 8, role: "UX Researcher" } ] } ]; export default function Example() { return ( <Select items={OPTIONS} label="Section"> {section => { const { role: sectionName, children } = section; return ( <SelectSection id={sectionName}> <Header>{sectionName}</Header> <Collection items={children}> {item => <SelectItem id={item.id}>{item.role}</SelectItem>} </Collection> </SelectSection> ); }} </Select> ); }

Icons

A select option can contain icons.

import { IconList, Select, SelectItem, Text } from "@hopper-ui/components"; import { SparklesIcon } from "@hopper-ui/icons"; export default function Example() { return ( <Select aria-label="list of options"> <SelectItem textValue="Designer"> <Text>Designer</Text> <IconList> <SparklesIcon /><SparklesIcon /><SparklesIcon /> </IconList> </SelectItem> <SelectItem textValue="Developer"> <SparklesIcon /> <Text>Developer</Text> </SelectItem> <SelectItem>Manager</SelectItem> </Select> ); }

End Icons

A select can contain icons at the end of an option.

import { IconList, Select, SelectItem, Text } from "@hopper-ui/components"; import { SparklesIcon } from "@hopper-ui/icons"; export default function Example() { return ( <Select aria-label="list of options"> <SelectItem textValue="Designer"> <Text>Designer</Text> <IconList slot="end-icon"> <SparklesIcon /><SparklesIcon /><SparklesIcon /> </IconList> </SelectItem> <SelectItem textValue="Developer"> <SparklesIcon slot="end-icon" /> <Text>Developer</Text> </SelectItem> <SelectItem>Manager</SelectItem> </Select> ); }

Loading

A select can have a loading state.

import { Select } from "@hopper-ui/components"; export default function Example() { return ( <Select aria-label="list of options" isLoading > {[]} </Select> ); }

Load on scroll

A select can load more items when scrolling within.

import { Select, SelectItem, useAsyncList } from "@hopper-ui/components"; interface Character { name: string; } export default function Example() { const list = useAsyncList<Character>({ async load({ signal, cursor }) { const res = await fetch(cursor || "https://pokeapi.co/api/v2/pokemon", { signal }); const json = await res.json(); return { items: json.results, cursor: json.next }; } }); return ( <Select aria-label="list of options" items={list.items} isLoading={list.isLoading} onLoadMore={list.loadMore} listBoxProps={{ maxHeight: "core_1280" }} > {item => { const { name } = item; return <SelectItem id={name}>{name}</SelectItem>; }} </Select> ); }

Selection indicator

A select can have a different selection indicator.

import { Select, SelectItem, Text, type Key } from "@hopper-ui/components"; import { useState } from "react"; export default function Example() { const [selectedKey, setSelectedKey] = useState<Key>("1"); return ( <Select aria-label="list of options" selectedKey={selectedKey} onSelectionChange={setSelectedKey} selectionIndicator="input" > <SelectItem textValue="Developer" id="1"> <Text>Developer</Text> <Text slot="description">Builds and maintains software.</Text> </SelectItem> <SelectItem textValue="Designer" id="2"> <Text>Designer</Text> <Text slot="description">Creates visual design solutions.</Text> </SelectItem> <SelectItem textValue="Manager" id="3"> <Text>Manager</Text> <Text slot="description">Leads teams and projects.</Text> </SelectItem> </Select> ); }

Description

A select item can have a description.

import { Select, SelectItem, Text } from "@hopper-ui/components"; export default function Example() { return ( <Select aria-label="list of options with a description"> <SelectItem textValue="Developer"> <Text>Developer</Text> <Text slot="description">Builds and maintains software.</Text> </SelectItem> <SelectItem textValue="Designer"> <Text>Designer</Text> <Text slot="description">Creates visual design solutions.</Text> </SelectItem> <SelectItem textValue="Manager"> <Text>Manager</Text> <Text slot="description">Leads teams and projects.</Text> </SelectItem> </Select> ); }

Props

Select

isLoading?
boolean

Whether the item is loading.

size?
ResponsiveProp<ListBoxItemSize>

A ListBoxItem can vary in size.

Defaults to sm.
isInvalid?
boolean

Whether or not the ListBoxItem is in an invalid state.

selectionIndicator?
SelectionIndicator

The selection indicator to use. Only available if the selection mode is not "none". When set to "input", the selection indicator will be an either a radio or checkbox based on the selection mode.

Defaults to check.
radioProps?
DecorativeRadioProps

The props for the Radio.

checkboxProps?
DecorativeCheckboxProps

The props for the Checkbox.

style?
CSSProperties | ((values: ListBoxItemRenderProps & { defaultStyle: CSSProperties; }) => CSSProperties)

The inline style for the element. A function may be provided to compute the style based on component state.

id?
Key

The unique id of the item.

value?
object

The object value that this item represents. When using dynamic collections, this is set automatically.

textValue?
string

A string representation of the item's contents, used for features like typeahead.

isDisabled?
boolean

Whether the item is disabled.

children?
ReactNode | ((values: ListBoxItemRenderProps & { defaultChildren: ReactNode; }) => ReactNode)

The children of the component. A function may be provided to alter the children based on component state.

className?
string | ((values: ListBoxItemRenderProps & { defaultClassName: string; }) => string)

The CSS className for the element. A function may be provided to compute the class based on component state.

href?
string

A URL to link to. See MDN.

hrefLang?
string

Hints at the human language of the linked URL. SeeMDN.

target?
HTMLAttributeAnchorTarget

The target window for the link. See MDN.

rel?
string

The relationship between the linked resource and the current page. See MDN.

download?
string | boolean

Causes the browser to download the linked URL. A string may be provided to suggest a file name. See MDN.

ping?
string

A space-separated list of URLs to ping when the link is followed. See MDN.

referrerPolicy?
HTMLAttributeReferrerPolicy

How much of the referrer to send when following the link. See MDN.

routerOptions?
undefined

Options for the configured client side router.

items?
Iterable<T>

Item objects in the section.

dependencies?
readonly any[]

Values that should invalidate the item cache when using dynamic collections.

align?
ResponsiveProp<MenuAlignment>

The alignment of the menu.

Defaults to start.
direction?
ResponsiveProp<MenuDirection>

The direction that the menu should open.

Defaults to bottom.
footer?
ReactNode

The footer of the select.

isAutoMenuWidth?
boolean

If true, the select menu will not be the width of the trigger and instead be the width of its contents.

isFluid?
ResponsiveProp<boolean>

If true, the select will take all available width.

Defaults to false.
listBoxProps?
ListBoxProps<T>

The list box props.

placeholder?
string

The placeholder text when the select is empty.

popoverProps?
PopoverProps

The props for the popover.

prefix?
ReactNode

An icon or text to display at the start of the select trigger.

renderValue?
((valueRenderProps: ValueRenderProps<T>) => ReactNode)

A function to render the value of the select. It will render the selected item's text by default.

shouldFlip?
boolean

Whether the element should flip its orientation (e.g. top to bottom or left to right) when there is insufficient room for it to render completely.

triggerProps?
(Omit<ButtonProps, keyof StyledSystemProps> & StyledSystemProps)

The props for the select's trigger.

validationBehavior?
"native" | "aria"

Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA.

Defaults to 'native'.
selectedKey?
Key | null

The currently selected key in the collection (controlled).

defaultSelectedKey?
Key

The initial selected key in the collection (uncontrolled).

autoComplete?
string

Describes the type of autocomplete functionality the input should provide if any. See MDN.

name?
string

The name of the input, used when submitting an HTML form.

isOpen?
boolean

Sets the open state of the menu.

defaultOpen?
boolean

Sets the default open state of the menu.

disabledKeys?
Iterable<Key>

The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with.

isRequired?
boolean

Whether user input is required on the input before form submission.

validate?
((value: Key) => true | ValidationError | null)

A function that returns an error message if a given value is invalid. Validation errors are displayed to the user when the form is submitted if validationBehavior="native". For realtime validation, use the isInvalid prop instead.

autoFocus?
boolean

Whether the element should receive focus on render.

description?
ReactNode

The helper message of the field.

errorMessage?
ReactNode | ((v: ValidationResult) => ReactNode)

The error message of the field.

label?
ReactNode

The label of the field.

necessityIndicator?
NecessityIndicator

Whether the required state should be shown as an asterisk or a label, which would display (Optional) on all non required field labels.

SelectSection

style?
CSSProperties

The inline style for the element.

children?
ReactNode | ((item: T) => ReactElement<any, string | JSXElementConstructor<any>>)

Static child items or a function to render children.

items?
Iterable<T>

Item objects in the section.

id?
Key

The unique id of the section.

value?
object

The object value that this section represents. When using dynamic collections, this is set automatically.

dependencies?
readonly any[]

Values that should invalidate the item cache when using dynamic collections.

className?
string

The CSS className for the element.

SelectItem

isLoading?
boolean

Whether the item is loading.

size?
ResponsiveProp<ListBoxItemSize>

A ListBoxItem can vary in size.

Defaults to sm.
isInvalid?
boolean

Whether or not the ListBoxItem is in an invalid state.

selectionIndicator?
SelectionIndicator

The selection indicator to use. Only available if the selection mode is not "none". When set to "input", the selection indicator will be an either a radio or checkbox based on the selection mode.

Defaults to check.
radioProps?
DecorativeRadioProps

The props for the Radio.

checkboxProps?
DecorativeCheckboxProps

The props for the Checkbox.

style?
CSSProperties | ((values: ListBoxItemRenderProps & { defaultStyle: CSSProperties; }) => CSSProperties)

The inline style for the element. A function may be provided to compute the style based on component state.

id?
Key

The unique id of the item.

value?
object

The object value that this item represents. When using dynamic collections, this is set automatically.

textValue?
string

A string representation of the item's contents, used for features like typeahead.

isDisabled?
boolean

Whether the item is disabled.

children?
ReactNode | ((values: ListBoxItemRenderProps & { defaultChildren: ReactNode; }) => ReactNode)

The children of the component. A function may be provided to alter the children based on component state.

className?
string | ((values: ListBoxItemRenderProps & { defaultClassName: string; }) => string)

The CSS className for the element. A function may be provided to compute the class based on component state.

href?
string

A URL to link to. See MDN.

hrefLang?
string

Hints at the human language of the linked URL. SeeMDN.

target?
HTMLAttributeAnchorTarget

The target window for the link. See MDN.

rel?
string

The relationship between the linked resource and the current page. See MDN.

download?
string | boolean

Causes the browser to download the linked URL. A string may be provided to suggest a file name. See MDN.

ping?
string

A space-separated list of URLs to ping when the link is followed. See MDN.

referrerPolicy?
HTMLAttributeReferrerPolicy

How much of the referrer to send when following the link. See MDN.

routerOptions?
undefined

Options for the configured client side router.

Migration Notes

Coming from Orbiter, you should be aware of the following changes:

  • Item has been renamed to SelectItem.
  • The selected value only includes text. If an icon or avatar is needed, customize it using the renderValue function.
  • There is no allowFlip. Use shouldFlip.
  • There is no allowPreventOverflow. This is done automatically.
  • There is no allowResponsiveMenuWidth. Use isAutoMenuWidth.
  • disabled has been renamed to isDisabled.
  • fluid has been renamed to isFluid.
  • open has been renamed to isOpen..
  • required has been renamed to isRequired.
  • A select cannot be read-only.
  • overlayProps has been removed. Use popoverProps instead.
  • Use isInvalid instead of validationState.
  • variant has been removed.
  • zIndex has been removed.
  • Custom tooltips are not supported.