Select
Select allows users to choose one option from a list of items in a Menu.
Anatomy
- Label: Title of the input.
- Input Container: Rectangular container that houses the icon and placeholder text.
- Placeholder Text (Optional): Placeholder text like “Select One” is typically displayed in the Select field. After the user makes a selection, the placeholder text is replaced with the user’s selection.
- Icon: Caret icon positioned to the right of the container visually distinguishes this as a Select input.
Usage Guidance
- Clicking or tapping anywhere in a Select opens the Menu.
- A checkmark icon indicates which value is currently selected in the list.
- Each Menu option should be distinct. If the option isn’t discrete, combine it with another option.
- The list of Menu options should be sorted in a logical order alphabetically, chronologically, or by order of importance.
When to Use
- Use Select as a form element where users are only allowed to select one item from a list of more than 7 predefined options.
- Typically, Selects work best when the list is between 7 to 15 items to prevent overwhelming the user with too many options.
When to Use Something Else
- Consider using a Switch if the only options are yes or no.
- For a list between 2 to 7 predefined options, consider using Radio Buttons to select one option or Checkboxes to select multiple options. Radio and Checkbox groups display all options upfront and do not require the user to interact with the input to view the list of options.
- Use a Prompt when the number of list items is large or unknown. Prompts have search capabilities and folders which provide users with the means to browse options. Prompts can be configured to support single or multi-select.
Examples
Basic Example
Select
supports a
dynamic API where you
pass an array of items via the items
prop and provide a render function to display the items. The
items may be provided as an
array of strings or an
array of objects.
Select
should be used in tandem with Form Field where the
Select
wraps the FormField
element and the FormField
element wraps the children of Select
to
meet accessibility standards. This ensures the label
text from FormField
is attached to the
Select.Input
and read out as a group for voiceover.
<Select items={options}><FormField label="Your Label"><Select.Input onChange={e => handleChange(e)} id="contact-select" /><Select.Popper><Select.Card><Select.List>{item => <Select.Item>{item.id}</Select.Item>}</Select.List></Select.Card></Select.Popper></FormField></Select>
Our example uses React state to track the
value of the Select
.
Hoisted Model
By default, Select
will create and use its own model internally. Alternatively, you may configure
your own model with useSelectModel
and pass it to Select
via the model
prop. This pattern is
referred to as
hoisting the model
and provides direct access to its state
and events
outside of the Select
component.
In this example, we set up external observation of the model state and create an external button to trigger an event to change the selected item.
Note: If your array of objects uses an id
property and a text
property there is no need to use
the helper functions of getId
or getTextValue
. The collection system and the Select
use these
properties by default for keyboard navigation and selected the id
based on the item clicked.
Selected Value: fax-3
Label Position
Set the labelPosition
prop of the wrapping FormField
to designate the position of the label
relative to the Select
. labelPosition
accepts the following values:
FormField.LabelPosition.Top
(Default)FormField.LabelPosition.Left
Required
Set the required
prop of the wrapping FormField
to true
to indicate that the field is
required. Labels for required fields are suffixed by a red asterisk.
Disabled
Set the disabled
prop of Select.Input
to prevent users from interacting with it.
Disabled Items
In order to disable items and prevent users from interacting with them:
Set the
nonInteractiveIds
prop ofSelect
to an array of disabled itemid
s. If your items are an array ofstrings
this will be just the text value. If your items are an array ofobjects
, this will be that value of theid
property. This will disable interaction for those items and exclude them from type-ahead.Set the
aria-disabled
attribute of all disabledSelect.Item
s totrue
. This ensures the items are styled as disabled.
The following example adds the string value of the items we want disable to nonInteractiveIds
and
sets aria-disabled
for the disabled items.
With Icons
Use Select.Item.Icon
to render an icon for a Select.Item
. The icon
prop for Select.Item.Icon
accepts system icons from @workday/canvas-system-icons-web
.
In order to render the icon for the selected item in the Select.Input
:
- Obtain a reference to the
model
by registering youritems
withuseSelectModel
. - Get the selected item:
const selectedItem = model.navigation.getItem(model.state.selectedIds[0], model)
- Pass the icon for the selected item to the input:
<Select.Input inputStartIcon={selectedItem.value.icon}>
Note:
data-id
onSelect.Item
must match theid
property in your array of objects. This ensures proper keyboard handling and type-ahead.
Note: that Select.Input
will only render an icon if an item is selected.
Grow
Set the grow
prop of the wrapping FormField
to true
to configure the Select.Input
to expand
to the width of its container.
Menu Height
Select.Card
has a default maximum height of 300px
to restrict the height of the dropdown menu.
Set its maxHeight
prop to override this value.
Ref Forwarding
Select.Input
supports ref forwarding. It will
forward ref
to its underlying <input type="text" role="combobox">
element.
Error States
Set the error
prop of the wrapping FormField
to FormField.ErrorType.Alert
or
FormField.ErrorType.Error
to set the Select
to the alert or error state, respectively. You will
also need to set the hintId
and hintText
props on the FormField
to meet accessibility
standards. You must set an id
attribute on the Select.Input
element that matches the value of
inputId
set on the FormField
element. These attributes ensure that the alert message is
associated to the Select
and read out by voiceover.
Note: The Select container component, Select
, must wrap FormField
to ensure Select.Input
is
styled correctly.
<Select items={options}><FormField label="Contact" inputId="contact-id-formfield"><Select.Input id="contact-id-formfield" />...</FormField></Select>
Alert
Use the alert state when a selection is valid but there is additional information.
Alert: Please choose a form of contact.
Error
Use the error state when the selection is no longer valid.
Error: Fax is disabled. Please choose a different option.
Initial Selected Item
You can set initialSelectedIds
to the value that you want initially selected.
Id: da594226446c11de98360015c5e6daf6
Value: English (United States)
Placeholder
You can change the placeholder text by passing in a string value to the placeholder
attribute on
the Select.Input
.
Fetching Dynamic Items
It's common to load items from a server call. Hoisting the model
and setting your items on state
allows you to pass those items to your model
. You can leverage React state to set your items on
load as well as displaying a placeholder indicating when items are loaded.
Note: In this case we need to use getId
and getTextValue
because our data doesn't have the
properties of id
or text
. Using these helper functions sets the serverId
to be id
and
label
to be text
.
Complex
When registering items in an array of objects, it's common to have the text that is displayed to the user be
different than an id. In this example, serverId
and label
properties need to be remapped to
id
and text
hence the usage of getId
and getTextValue
. If your object has the properties
text
and id
, there would be no need for this.
Id:
Value:
Note: By default, the identifier and text value are id
and text
properties respectively. If
your data object for each item is different, provide a getId
or getTextValue
function to the
model config. For example:
const items = [{serverId: '1',label: 'First Option',},];<Select items={items} getId={item => item.serverId} getTextValue={item => item.label}>{/* etc */}</Select>;
When to use getId
, or getTextValue
getId
: This is an optional function to return the id of an item. If not provided, the default function will return theid
property from the object of each item. If you did not provideitems
, do not override this function. Instead provide static items via JSX. the list will create an internal array of items whereid
is the only property and the defaultgetId
will return the desired result. Note: If your array of objects has a different property forid
, likeserverId
, use this function to set the id.const options = [{text: 'Pizza', serverId: 'pizza-1'}, {text: 'Cheeseburger', serverId: 'cheeseburger'}]<Select items={options} getId={(item) => item.serverId}><FormField label="Your Label"><Select.Input onChange={e => handleChange(e)} id="contact-select" /><Select.Popper><Select.Card><Select.List>{item => <Select.Item>{item.text}</Select.Item>}</Select.List></Select.Card></Select.Popper></FormField></Select>getTextValue
: Optional function to return the text representation of an item. If not provided, the default function will return thetext
property of the object of each item or an empty string if there is notext
property. If you did not provideitems
, do not override this function. Note: If your array of objects has a different property fortext
, likelabel
, use this function to set the text.const options = [{label: 'Pizza', id: 'pizza-1'}, {label: 'Cheeseburger', id: 'cheeseburger'}]<Select items={options} getTextValue={(item) => item.label}><FormField label="Your Label"><Select.Input onChange={e => handleChange(e)} id="contact-select" /><Select.Popper><Select.Card><Select.List>{item => <Select.Item>{item.label}</Select.Item>}</Select.List></Select.Card></Select.Popper></FormField></Select>
Component API
Select
Use Select
to allow users to choose an option from a list or type characters to select a matching option.
Note: Select
must wrap FormField
and FormField
must wrap all Select
children to ensure proper accessibility.
<Select items={options}><FormField label="Your Label"><Select.Input onChange={e => handleChange(e)} id="contact-select" /><Select.Popper><Select.Card><Select.List>{item => <Select.Item>{item.id}</Select.Item>}</Select.List></Select.Card></Select.Popper></FormField></Select>
Props
Props extend from . If a model
is passed, props from SelectModelConfig
are ignored.
Name | Type | Description | Default |
---|---|---|---|
theme |
| ||
children | ReactNode | Children of the | |
model |
| Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
Select.Input
Select.Input
renders a that handles keyboard navigation and interaction defined by WAI.
This component can either be controlled or uncontrolled.
<Select items={options}><FormField label="Contact"><Select.Input onChange={(event) => handleChange(event)}>...</FormField></Select>
Props
Props extend from . Changing the as
prop will change the element interface.
Name | Type | Description | Default |
---|---|---|---|
inputStartIcon |
| The Icon to render at the start of the | |
error |
| The type of error associated with the TextInput (if applicable). | |
width | number | string | The width of the TextInput. | |
theme |
| ||
grow | boolean | True if the component should grow to its container's width. False otherwise. | |
cs |
| The
| |
children | React.ReactNode | ||
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. |
|
ref | React.Ref<R = > | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model |
| Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useSelectInput
useSelectInput
extends and
and adds type ahead functionality and Select-specific keyboard support.
(
(
model: ,
elemProps: {
keySofar: string;
placeholder: string;
},
ref: React.Ref
) => {
onKeyDown: (event: ) => void;
onChange: (event: <>) => void;
autoComplete: 'off';
onFocus: () => void;
textInputProps: {
ref: <>;
};
ref: (instance: | null) => void;
defaultValue: string | undefined;
},
,
,
,
)
Select.Card
Select.Card
renders a . You have access to all
Card
props.
Note: The card will be the width of its corresponding Select.Input
.
<Select item={options}><FormField label="Your Label"><Select.Input onChange={(event) => handleChange(event)}><Select.Popper><Select.Card>...</Select.Card></Select.Popper></FormField></Select>
Layout Component
Select.Card
supports all props from thelayout component.
Props
Props extend from div. Changing the as
prop will change the element interface.
Name | Type | Description | Default |
---|---|---|---|
cs |
| The
| |
children | React.ReactNode | ||
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | div |
ref | React.Ref<R = div> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model |
| Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useSelectCard
Sets the width of the SelectCard
to the Select.Input
width.
(
model: ,
elemProps: {},
ref: React.Ref
) => {
width: number;
}
Select.Item
Select.Item
renders a with aria role of
option
. You can optionally render a Icon
.
<Select item={options}><FormField label="Your Label"><Select.Input onChange={(event) => handleChange(event)}><Select.Popper><Select.Card><Select.List>{(item) => <Select.Item><Select.Item.Icon icon={icon} />{item}</Select.Item>}</Select.List</Select.Card></Select.Popper></FormField></Select>
Props
Props extend from li. Changing the as
prop will change the element interface.
Name | Type | Description | Default |
---|---|---|---|
children | ReactNode | ||
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | li |
ref | React.Ref<R = li> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model |
| Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
Model
useSelectModel
SelectModel
extends the . Selecting items from
the menu will dispatch an
input event on the
input which should work with form libraries, automation and autofill.
const model = useSelectModel({items: ['Mobile', 'Phone', 'E-Mail']})<Select model={model}>...</Select>
useSelectModel (config: ):
Specifications
Given | When | Then |
---|---|---|
given the "Disabled Options" story is rendered |
| |
given the "Disabled Options" story is rendered |
| |
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
given the "Disabled Options" story is rendered |
|
|
Accessibility Guidelines
Keyboard Interaction
Each Select must have a focus indicator that is highly visible against the background and against the non-focused state. Refer to Accessible Colors for more information.
Select must support the following keyboard interactions:
Tab
: focus the Select componentEnter
orSpace
: open the Select list box and focus the first optionEsc
: dismiss the Select list box and focus the Select componentUp Arrow
orDown Arrow
: focus the previous or next option respectivelyCharacter Key
: focus options matching character keyHome
orFn + Up Arrow
: focus first optionEnd
orFn + Down Arrow
: focus last option
Screen Reader Interaction
Select must communicate the following to users:
- This component is a “combo” or “combobox”
- The associated label
- The currently selected value
- The “collapsed” or “expanded” state
- When opened, there is a list of ‘X’ items
- When opened, the name of the active option
- When opened, the position “X of Y” for the active option
Design Annotations Needed
No design annotations required for Select.
Implementation Markup Needed
The Select component is built around the
ARIA Combobox v1.2 specification for Select-Only.
Support for this component may be limited by browser vendors and/or screen readers. Also, note
any reference to “menu” on this page does not refer to an ARIA menu
pattern. The Select component
is using an ARIA listbox
pattern for the options.
- A
<label>
element must be used with afor
attribute referencing the uniqueid
value of the Select input. - Select input must have a
required
attribute when the field is required for form submission. - Select input must have an
aria-describedby
attribute referencing the uniqueid
value of the inline hint text below the field. - Select input must have an
aria-invalid=”true”
attribute when the field has an error condition. - Select input must have a
disabled
attribute when the field is disabled.
Content Guidelines
- The list of Menu items should be scannable, with concise labels written in title case. Don’t write sentences and omit articles (a, an, the) unless needed for clarity. For more detailed information on how to write Menu items, refer to the Drop-down Menus section of the Content Style Guide.
- Placeholder text for a Select must begin with the verb “Select”. Refer to the guidelines on Placeholder Text in the Content Style Guide for more tips on how to write placeholder text.
Can't Find What You Need?
Check out our FAQ section which may help you find the information you're looking for.
FAQ Section