packages/react-components/react-combobox/stories/src/Dropdown/DropdownAccessibility.mdx
import { Meta } from '@storybook/addon-docs/blocks'; import clickImg from '../assets/Dropdown/dropdown-click.png'; import collapsedImg from '../assets/Dropdown/dropdown-collapsed.png'; import hoverImg from '../assets/Dropdown/dropdown-hover.png'; import keySelectImg from '../assets/Dropdown/dropdown-key-select.png'; import multiselect1Img from '../assets/Dropdown/dropdown-multiselection1.png'; import multiselect2Img from '../assets/Dropdown/dropdown-multiselection2.png'; import navImg from '../assets/Dropdown/dropdown-nav.png'; import openImg from '../assets/Dropdown/dropdown-open.png'; import optionHoverImg from '../assets/Dropdown/dropdown-option-hover.png'; import selectedOpenImg from '../assets/Dropdown/dropdown-selected-open.png'; import semanticsImg from '../assets/Dropdown/dropdown-semantics.png'; import tabbingImg from '../assets/Dropdown/dropdown-tabbing.png';
<Meta title="Concepts/Developer/Accessibility/Components/Dropdown" />Dropdown is one of three form selection components that display the current selection, and allow a user to expand a popup to modify the selection. The other two are Select and Combobox.
The semantics and behavior are roughly similar to a more complex version of the Select component (an HTML <select> element), but with more functionality and full control over styling. Unlike Combobox, Dropdown does not allow text input. Dropdown supports both single-selection and multi-selection.
Dropdown is a more feature-rich version of Select, which comes at the cost a larger code footprint, and less robust support for accessibility compared to the native <select> element.
Use Dropdown when any of the following are required:
Otherwise, Select is recommended for performance, accessibility, and native-feeling mobile support.
Combobox allows text input, which enables filtering and freeform values. This is a better fit for use cases with a large number of options, or where the user may want to type a value directly without interacting with the popup.
Select or Dropdown should be used over Menu when creating a standalone control for selecting values. Menu should be used when the purpose is to allow the user to perform an immediate action on the page, or when the control is embedded within a parent Menu.
Examples of appropriate Menu usage include:
Checkboxes are significantly more usable and accessible than multiselect comboboxes for smaller numbers of choices. Consider using a checkbox group over Dropdown if there are less than 10 options.
Authors must provide label text for Dropdown. The recommended pattern for Fluent form controls is to use the Label component like this:
<Label htmlFor="dropdown-id">Favorite Fruit</Label>
<Dropdown id="dropdown-id">
<Option>Apple</Option>
<Option>Banana</Option>
</Dropdown>
Other options include:
aria-label="label text string" on the <Dropdown> componentaria-labelledby="label-id" on the <Dropdown> component, pointing to the id of label textThe placeholder prop is not a substitute for a label. It is no longer displayed when a value is selected, while labels must be persistently visible and exposed to the user.
The following content types should not be used within children or slots of Dropdown:
<Option>.The following content types should not be used within children or slots of Option:
<Option>.Focusable and interactive content is prohibited based on the semantics of Dropdown and Option, and will cause issues for screen reader users. Focusable items within the popup will additionally not be keyboard accessible.
The following content types may be used within children and slot content in Dropdown and Option:
<div> and <span>, without tabindex or role properties<Text> componentBy default, the popup renders in its own layer at the end of the DOM to ensure it appears above all other UI, and is not clipped by containers with overflow: hidden or overflow: scroll. This causes an issue for people who use iOS VoiceOver (Apple's touch-based screen reader), since it strictly follows DOM order when swiping from one control to the next. This makes it difficult to reach the options popup after opening the Dropdown.
If possible, we recommend setting inlinePopup={true}, which will render the popup directly after the Dropdown button in the DOM for better VoiceOver touch support.
By default, the <Option> component calculates its text value from its children. This works if the children are a simple string, like this:
<Option>Simple text string</Option>
However, if the <Option> contains JSX, this will not work correctly. If that is the case, provide a string value with the value prop:
<Option value="Simple text string">
<CheckRegular />
<span>Simple text string</span>
</Option>
Dropdown uses string values to handle jumping between options based on alphanumeric keyboard input, so value must match the visual text displayed within the Option.
The filled-lighter, filled-darker, and underline all have contrast requirements for their background color:
filled-lighter and filled-darker variants must both be placed over background colors dark enough to meet 3:1 contrast against the Dropdown button's background color.underline must be placed over a light enough background for the placeholder and value text to meet 4.5:1 contrast against the page background.| Role | States and properties |
|---|---|
| 1. combobox | type="button" |
aria-haspopup="listbox" | |
aria-activedescendant="active-option-id" | |
aria-expanded="true/false" | |
| 2. listbox | - |
| 3. option | aria-selected="true/false" |
| wrapper (no role) | aria-owns="listbox-id"* |
** * putting aria-owns on the wrapping element moves the listbox immediately after the trigger in the accessibility tree, even though it is rendered at the end of the DOM. For all screen readers but VoiceOver, this enables virtual cursor navigation between the trigger and listbox/options. **
| Name | Role | States and properties |
|---|---|---|
| (1) Best fruit | combobox | aria-expanded="false" |
| Name | Role | States and properties |
|---|---|---|
| (1) Best fruit | combobox | aria-expanded="true" |
| Key | Result |
|---|---|
| <kbd>Enter</kbd> | Opens popup with first option in focus |
| <kbd>Space</kbd> | Opens popup with first option in focus |
| <kbd>Up</kbd> or <kbd>Down</kbd> arrow | Opens popup with first option in focus |
| Any printable character | Opens popup with focus on first option matching that character |
| <kbd>Esc</kbd> or <kbd>Alt</kbd> + <kbd>Up</kbd> arrow | Closes popup without modifying selection, and keeps dropdown in focus |
When one or more options are already selected, focus will move to the most recently selected option when opened.
| Name | Role | States and properties |
|---|---|---|
| (2) Best fruit | combobox | aria-expanded="true" |
| (3) Banana | option | aria-selected="true" |
| Name | Role | States and properties |
|---|---|---|
| (2) - | listbox | - |
| (3) Banana | option | aria-selected="false" |
| Key | Result |
|---|---|
| <kbd>Up</kbd> arrow | Moves focus to the previous option, if one exists |
| <kbd>Down</kbd> arrow | Moves focus to the next option, if one exists |
| <kbd>Home</kbd> | Moves focus to the first option |
| <kbd>End</kbd> | Moves focus to the last option |
| <kbd>PageUp</kbd> | Moves focus up 10 options, or to the first option |
| <kbd>PageDown</kbd> | Moves focus down 10 options, or to the last option |
| Any printable character | Moves focus to the next option matching that character |
| Name | Role | States and properties |
|---|---|---|
| (1) Banana | option | aria-selected="false" |
| Key | Result |
|---|---|
| <kbd>Enter</kbd> or <kbd>Space</kbd> | Selects the focused option and closes the popup |
| <kbd>Tab</kbd> | Selects the focused option, closes the popup, and moves focus after the dropdown |
| <kbd>Shift</kbd> + <kbd>Tab</kbd> | Selects the focused option, closes the popup, and moves focus before the dropdown |
| Name | Role | States and properties |
|---|---|---|
| (2) Best fruit | combobox | aria-expanded="false" |
Unlike single-select behavior, mutliselect Dropdowns do not close automatically after a selection is made, unless using <kbd>Tab</kbd> or <kbd>Shift</kbd> + <kbd>Tab</kbd>.
| Name | Role | States and properties |
|---|---|---|
| (1a) Banana | option | aria-selected="false" |
| (1b) Banana | option | aria-selected="true" |
| Key | Result |
|---|---|
| <kbd>Enter</kbd> or <kbd>Space</kbd> | Toggles selection on or off for focused option |
| <kbd>Tab</kbd> | Toggles selection on or off for focused option, closes the popup, and moves focus after the dropdown |
| <kbd>Shift</kbd> + <kbd>Tab</kbd> | Toggles selection on or off for focused option, closes the popup, and moves focus before the dropdown |
Dropdown fully relies on native browser behavior for Windows contrast themes. All borders, icons, and text adapt to the user-selected theme colors without modifying styles in a media query.
The focus underline's growing animation does not run when prefers-reduced-motion is true.
aria-owns