Skip to main content

Select

The Select component allows for a single option to be selected from a dropdown list. The Select component can be searchable or non-searchable.

The Item and Section components are re-exported in Kyber from the @react-stately/collections library.

Uncontrolled​

By default, Select is an uncontrolled component. The defaultSelectedKey prop can be used to set the initial selected key.

Result
Loading...
Live Editor
<Select label="Select" defaultSelectedKey="twenty-four">
	<Item key="one">One</Item>
	<Item key="two">Two</Item>
	<Item key="three">Three</Item>
	<Item key="four">Four</Item>
	<Item key="five">Five</Item>
	<Item key="six">Six</Item>
	<Item key="seven">Seven</Item>
	<Item key="eight">Eight</Item>
	<Item key="nine">Nine</Item>
	<Item key="ten">Ten</Item>
	<Item key="eleven">Eleven</Item>
	<Item key="twelve">Twelve</Item>
	<Item key="thirteen">Thirteen</Item>
	<Item key="fourteen">Fourteen</Item>
	<Item key="fifteen">Fifteen</Item>
	<Item key="sixteen">Sixteen</Item>
	<Item key="seventeen">Seventeen</Item>
	<Item key="eighteen">Eighteen</Item>
	<Item key="nineteen">Nineteen</Item>
	<Item key="twenty">Twenty</Item>
	<Item key="twenty-one">Twenty One</Item>
	<Item key="twenty-two">Twenty Two</Item>
	<Item key="twenty-three">Twenty Three</Item>
	<Item key="twenty-four">Twenty Four</Item>
</Select>

With sections​

Result
Loading...
Live Editor
<Select label="Select with Sections">
	<Section key="header-1" title="Fruit">
		<Item key="apples">Apples</Item>
		<Item key="bananas">Bananas</Item>
		<Item key="oranges">Oranges</Item>
	</Section>
	<Section key="header-2" title="Vegetables">
		<Item key="beans">Beans</Item>
		<Item key="cabbages">Cabbages</Item>
		<Item key="onions">Onions</Item>
	</Section>
	<Section key="header-3" title="Cheese">
		<Item key="cheddar">Cheddar</Item>
		<Item key="mozzarella">Mozzarella</Item>
		<Item key="swiss">Swiss</Item>
	</Section>
</Select>

As a searchable Select​

The searchable prop allows the user to search for items in the list. If the value is not found in the list the input value will be cleared on field blur.

Result
Loading...
Live Editor
<div data-testid="pw-searchable-select">
	<Select label="Searchable Select" searchable>
		<Item key="one">One</Item>
		<Item key="two">Two</Item>
		<Item key="three">Three</Item>
		<Item key="four">Four</Item>
	</Select>
</div>

Controlled​

Controlled components are useful when you need to respond to changes in the selected key. For example, if you need to update the selected key based on user input, you can use the onSelectionChange prop to update the selected key.

Result
Loading...
Live Editor
function Example() {
	const [selectedKey, setSelectedKey] = useState('one');

	return (
		<Select
			label="Controlled Select"
			searchable
			selectedKey={selectedKey}
			onSelectionChange={setSelectedKey}
		>
			<Item key="one">One</Item>
			<Item key="two">Two</Item>
			<Item key="three">Three</Item>
			<Item key="four">Four</Item>
		</Select>
	);
}

With dividers​

Result
Loading...
Live Editor
<Select label="Select with Dividers">
	<Item key="one">One</Item>
	<Item key="two">Two</Item>
	<Dropdown.Divider />
	<Item key="three">Three</Item>
	<Item key="four">Four</Item>
</Select>
Result
Loading...
Live Editor
<Select label="Select with Sections">
	<Section key="header-1" title="Fruit">
		<Item key="apples">Apples</Item>
		<Item key="bananas">Bananas</Item>
		<Item key="oranges">Oranges</Item>
	</Section>
	<Dropdown.Divider />
	<Section key="header-2" title="Vegetables">
		<Item key="beans">Beans</Item>
		<Item key="cabbages">Cabbages</Item>
		<Item key="onions">Onions</Item>
	</Section>
	<Dropdown.Divider />
	<Section key="header-3" title="Cheese">
		<Item key="cheddar">Cheddar</Item>
		<Item key="mozzarella">Mozzarella</Item>
		<Item key="swiss">Swiss</Item>
	</Section>
</Select>

With multiline items​

Result
Loading...
Live Editor
<Select label="Select with multiline items">
	<Item key="one" title="One">
		Item description 1
	</Item>
	<Item key="two" title="Two">
		Item description 2
	</Item>
	<Item key="three" title="Three">
		Item description 3
	</Item>
	<Item key="four" title="Four">
		Item description 4
	</Item>
</Select>

With empty/null items​

react-aria does not explicitly support empty/null items. However, Kyber provides a NULLABLE_ITEM_KEY constant that can be used to set the key of an item you want to resolve to null. This is useful when you want to allow the user to select an empty value. In this case the selected key will be set to null when the empty item is selected. The following examples use a unicode non-breaking space character as the empty item. But any content can be used.

Non-searchable​

Result
Loading...
Live Editor
function Example() {
	const [selectedKey, setSelectedKey] = useState('one');

	return (
		<Select
			label="Non-searchable Select with empty values"
			selectedKey={selectedKey}
			onSelectionChange={setSelectedKey}
		>
			<Item key={NULLABLE_ITEM_KEY}>{'\u00A0'}</Item>
			<Item key="one">One</Item>
			<Item key="two">Two</Item>
			<Item key="three">Three</Item>
			<Item key="four">Four</Item>
		</Select>
	);
}

Searchable​

Result
Loading...
Live Editor
function Example() {
	const [selectedKey, setSelectedKey] = useState('one');

	return (
		<Select
			label="Searchable Select with empty values"
			searchable
			selectedKey={selectedKey}
			onSelectionChange={setSelectedKey}
		>
			<Item key={NULLABLE_ITEM_KEY}>{'\u00A0'}</Item>
			<Item key="one">One</Item>
			<Item key="two">Two</Item>
			<Item key="three">Three</Item>
			<Item key="four">Four</Item>
		</Select>
	);
}

With portal​

The container prop can be used to render the menu within a specific DOM element with a portal. This is useful when you want to render the menu outside of the current component tree, particularly if your Select is within a scrollable area and is getting clipped.

Result
Loading...
Live Editor
function Example() {
	return (
		<>
			<Select label="Select" container={() => document.querySelector('#container')}>
				<Item key="one">One</Item>
				<Item key="two">Two</Item>
				<Item key="three">Three</Item>
				<Item key="four">Four</Item>
			</Select>
			<div id="container" />
		</>
	);
}

Within a form​

Non-searchable​

Result
Loading...
Live Editor
<div data-testid="pw-non-searchable-select-within-form">
	<Form
		initialValues={{}}
		onSubmit={async (values, { setSubmitting }) => {
			console.log(values);
			setSubmitting(false);
		}}
		validationSchema={object().shape({ select: string().required() })}
	>
		<FormField>
			<Select label="Non-searchable Select" name="select">
				<Item key="one">One</Item>
				<Item key="two">Two</Item>
				<Item key="three">Three</Item>
				<Item key="four">Four</Item>
			</Select>
		</FormField>
	</Form>
</div>

Searchable​

Result
Loading...
Live Editor
<div data-testid="pw-searchable-select-within-form">
	<Form
		initialValues={{}}
		onSubmit={async (values, { setSubmitting }) => {
			console.log(values);
			setSubmitting(false);
		}}
		validationSchema={object().shape({ select: string().required() })}
	>
		<FormField>
			<Select label="Searchable Select" name="select" searchable>
				<Item key="one">One</Item>
				<Item key="two">Two</Item>
				<Item key="three">Three</Item>
				<Item key="four">Four</Item>
			</Select>
		</FormField>
	</Form>
</div>

Analytics​

The Select component is trackable through Kyber Analytics. This is the default analytics config.

export default {
value: 'Select',
actions: {
onSelectionChange: { type: 'SELECT_SELECTION_CHANGE', payload: 'Change' },
onChange: { type: 'SELECT_CHANGE', payload: 'Change' },
},
};

Props​