src/hooks/MIGRATION_V7.md
Since version 7.0.0 Downshift follows the (ARIA 1.2 guideline for the combobox)[select-aria]. This brought a series of changes that are considered breaking, both to the API and the behaviour of downshift's useSelect and useCombobox hooks. The list of changes, as well as the migration itself, is detailed below.
Since ARIA 1.2, focus stays on the trigger element at all times. (Previously)deprecated-select-aria, it toggled between the trigger and the menu depending on the open state of the select element. If any of your custom implementation involved the focus on the menu element, please change it as the focus stays on the trigger even when the menu is open.
Similar to 1.1, useSelect communicates to the screen reader the currently highlighted item via the aria-activedescendant attribute. However, since now the focus is always on the trigger element, this attribute, along with others, have shifted as shown below:
Event changes occured because of the focus shift, as well as new accessibility pattern recommendantions.
getToggleButtonProps additions:
getToggleButtonProps changes:
getMenuProps removals:
As a consequence of the event changes, the stateChangeTypes received in the stateReducer and on${statePropery}Change received the following modifications:
Please change your reducer / onChange code accordingly. For instance:
function stateReducer(state, actionAndChanges) {
const {changes, type} = actionAndChanges
switch (type) {
case useSelect.stateChangeTypes.MenuKeyDownEnter:
case useSelect.stateChangeTypes.MenuKeyDownSpaceButton:
case useSelect.stateChangeTypes.ItemClick:
return {
...changes,
isOpen: true, // keep the menu open after selection.
}
default:
return changes
}
}
Becomes:
function stateReducer(state, actionAndChanges) {
const {changes, type} = actionAndChanges
switch (type) {
case useSelect.stateChangeTypes.ToggleButtonKeyDownEnter:
case useSelect.stateChangeTypes.ToggleButtonKeyDownSpaceButton:
case useSelect.stateChangeTypes.ItemClick:
return {
...changes,
isOpen: true, // keep the menu open after selection.
}
default:
return changes
}
}
Another thing to mention is that, since ARIA 1.2 does not recommend a
<button>element for the toggle button anymore, Enter and SpaceBar do not perform click events out of the box, when the menu is closed. Consequently, we are triggering these events manually. For backwards compatibility to pre v7, when menu is closed and toggle element receives Enter or SpaceBar key event, it will trigger auseSelect.stateChangeTypes.ToggleButtonClicktype change.
The prop circularNavigation has been removed. Navigation inside the menu is standard and non-circular. If you wish to make it circular, use the stateReducer:
function stateReducer(state, actionAndChanges) {
const {changes, type} = actionAndChanges
switch (type) {
case useSelect.stateChangeTypes.ToggleButtonKeyDownArrowDown:
if (state.highlightedIndex === items.length - 1) {
return {...changes, highlightedIndex: state.highlightedIndex}
} else {
return changes
}
case useSelect.stateChangeTypes.ToggleButtonKeyDownArrowUp:
if (state.highlightedIndex === 0) {
return {...changes, highlightedIndex: state.highlightedIndex}
} else {
return changes
}
default:
return changes
}
}
The biggest change in ARIA 1.2 is that the input wrapper element does not receive the combobox role attributes anymore. Previouslydeprecated-combobox-aria, the role of combobox, as well as other HTML attributes, had to be added on the input parent element. Some attributes that belonged to the wrapper element are now added on the input element. The changes are as follows:
As a result of the 1.2 pattern, there are a few event handling changes detailed below.
getInputProps additions:
getInputProps changes:
As a consequence of the event changes, the stateChangeTypes received in the stateReducer and on${statePropery}Change received the following additions:
You don't need to change your reducer if you want to keep the 1.2 functionality provided by default. However, if you want to keep the menu closed when the input gets focus, you can do:
function stateReducer(state, actionAndChanges) {
const {changes, type} = actionAndChanges
switch (type) {
case useCombobox.stateChangeTypes.InputFocus:
return {
...changes,
isOpen: state.isOpen, // keep the menu closed when input gets focused.
}
default:
return changes
}
}
The prop circularNavigation has been removed. Navigation inside the menu is standard and circular. If you wish to make it non-circular, use the stateReducer:
function stateReducer(state, actionAndChanges) {
const {changes, type} = actionAndChanges
switch (type) {
case useCombobox.stateChangeTypes.InputKeyDownArrowDown:
if (state.highlightedIndex === items.length - 1) {
return {...changes, highlightedIndex: state.highlightedIndex}
}
break
case useCombobox.stateChangeTypes.InputKeyDownArrowUp:
if (state.highlightedIndex === 0) {
return {...changes, highlightedIndex: state.highlightedIndex}
}
break
default:
return changes
}
return changes
}