-
Notifications
You must be signed in to change notification settings - Fork 842
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[EuiSuperSelect] Fix various focus and accessibility issues: The Sequel, Part Two #7650
Conversation
…label - mimicking default `<select>` component
- requires disabling the default focus trap, since this component handles so much of its own focus manually
- open/close keyboard a11y (+ refocus class check) - tab to select, escape should not select - form row focus, which was fixed 2 ish years ago
…options` array - would previously stop / not skip past disabled options like native selects should
// Note: this component purposely does not cycle arrow key navigation | ||
// to match native <select> elements | ||
if (direction === ShiftDirection.BACK) { | ||
targetElementIndex = | ||
currentIndex === 0 ? this.itemNodes.length - 1 : currentIndex - 1; | ||
targetElementIndex = currentIndex - 1; | ||
} else { | ||
targetElementIndex = | ||
currentIndex === this.itemNodes.length - 1 ? 0 : currentIndex + 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Open to feedback on this opinionated change - obviously our native <select>
component doesn't support cycling/looping between the list of options, but our EuiComboBox
and EuiSelectable
components do.
I leaned towards removing the behavior so that EuiSuperSelect
more closely matches a native <select>
(but with JSX rendering) and also to reduce the needed logic within the component, but feel free to shout if you feel strongly otherwise!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a reasonable change if we want it to be closer related to EuiSelect
👍
And in doubt we can still iterate on it in the future if the need arises for cycling the options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to @mgadewoll on this item.
Preview staging links for this PR:
|
💚 Build Succeeded
cc @cee-chen |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚢 🐈⬛ Awesome changes to ensure a more accessible component! 🎉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary
One change request for you @cee-chen.
In testing I noticed some unpredictability with Safari + VO on MacOS Ventura. This wasn't a regression from the prior production code, just a flaky handling of focus. VO acts like it's re-rendering and recycles itself. I did not experience this with any other pairing.
Screen reader test pairings
- MacOS + Safari + VO
- Win10 + Firefox + NVDA
- Win10 + Chrome + NVDA
- Win10 + Chrome + JAWS
- iOS + Safari + VO
// Note: this component purposely does not cycle arrow key navigation | ||
// to match native <select> elements | ||
if (direction === ShiftDirection.BACK) { | ||
targetElementIndex = | ||
currentIndex === 0 ? this.itemNodes.length - 1 : currentIndex - 1; | ||
targetElementIndex = currentIndex - 1; | ||
} else { | ||
targetElementIndex = | ||
currentIndex === this.itemNodes.length - 1 ? 0 : currentIndex + 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to @mgadewoll on this item.
// Refocus back to the toggling control button on popover close | ||
requestAnimationFrame(() => { | ||
this.controlButtonRef.current?.focus(); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Safari + VO is flaky on this function. It acts like there's a full refresh happening, because the introductory message "Welcome to VoiceOver" is being announced. I have a feeling this might be another event handler confounding the focus behavior. I did not witness this behavior with NVDA, JAWS or iOS Safari + VoiceOver, just the desktop.
This doesn't introduce regression that I can say definitively, but we'll want to keep an ear for feedback from the community.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's super weird, I didn't experience that during my testing (not to be the "it works on my machine" developer 🙈). Just to clarify, you're OK with leaving this for now and keeping an eye on feedback to see if we need to fix it later?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I'm okay leaving as is, and listening for feedback. I had a thought my phantom issues could be Chrome being open in the background and causing just enough CPU load to adversely affect VO.
|
||
const buttonId = hasFormLabel ? `${id}-button` : undefined; | ||
const ariaLabelledBy = hasFormLabel | ||
? `${buttonId} ${formLabelId}` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to reliably have the form label first, then the button label when we're building the aria-labelledby
attribute? I think it makes more sense to hear "Status, Minor" because that feels like the key: value
relationship order.
If it can be swapped, let's go for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kept it in this order to match how native <select>
s work (at least for Mac+VO) - see https://eui.elastic.co/#/forms/form-controls#select.
Is the order different on Windows/JAWS/NVDA etc? If so I'm down to swap it since those are more used screen readers. What I'm going for is 1:1 screen reader experience with EuiSelect
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's good enough reason for me. I'm much for consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I responded in thread to two questions, I have no issue approving as is.
Thanks y'all!! |
`v93.5.2` ⏩ `v93.6.0` --- ## [`v93.6.0`](https://github.com/elastic/eui/releases/v93.6.0) - Updated `EuiBreadcrumb` styles to improve visual distinction of clickable breadcrumbs ([#7615](elastic/eui#7615)) **Deprecations** - Deprecated `color` prop on `EuiBreadcrumb` ([#7615](elastic/eui#7615)) **Bug fixes** - Fixed `EuiComboBox` to correctly select full matches within groups via the `Enter` key ([#7658](elastic/eui#7658)) **Accessibility** - Updated `EuiHeaderBreadcrumb` styles to ensure min. required color contrast ([#7643](elastic/eui#7643)) - `EuiSuperSelect` now correctly reads out parent `EuiFormRow` labels to screen readers ([#7650](elastic/eui#7650)) - `EuiSuperSelect` now more closely mimics native `<select>` behavior in its keyboard behavior and navigation ([#7650](elastic/eui#7650)) - `EuiSuperSelect` no longer strands keyboard focus on close ([#7650](elastic/eui#7650)) - `EuiSuperSelect` now correctly allows keyboard navigating past disabled options in the middle of the options list ([#7650](elastic/eui#7650))
…test (#180457) closes #180424 The SuperSelect EUI component started showing an extra `<span/>` when it displayed the selected value ([change](https://github.com/elastic/eui/blob/d08f49cf1f0ee6a31301ade914a2d06143d4a3d4/src/components/form/super_select/super_select_control.tsx#L195-L201) from elastic/eui#7650) . This caused a problem in a test that checks the agent policy name strictly. I changed the test to see if the text `contains` the string instead of `has` it. I checked the flow and found it doesn't affect the data sent to the API. Also, the `euiScreenReaderOnly` property hides this extra span in the regular UI so it is not visible to users. 
Summary
The year was 2021, and a younger and much more foolish Cee thought they were squashing bugs and taking names in #5097.
But as it turns out, EuiSuperSelect is kind of an a11y tire fire and needed much more than that!
Fixes in this PR:
EuiSuperSelect
now announces parentEuiFormRow
labels, the same way anEuiSelect
component would (thank you @cleydyr for pointing this out to us!)EuiSuperSelect
no longer strands keyboard focus on popover close 😬EuiSuperSelect
's popover can now also be opened onSpace
keypress (same asEuiSelect
)EuiSuperSelect
's options can now be selected viaTab
keypress (same asEuiSelect
)EuiSuperSelect
no longer cycles through its options when pressing arrow up or arrow down at the top or bottom of the options list (same asEuiSelect
)EuiSuperSelect
now correctly keyboard navigates up/down past disabled options in the middle of the options list (we didn't notice this bug in our docs examples previously because the disabled options were at the start or end of the options list 🤦)QA
<select>
wouldSpace
to open the dropdown list andTab
to select an optionGeneral checklist
- [ ] Checked in both light and dark modes- [ ] Checked in mobile- [ ] If applicable, added the breaking change issue label (and filled out the breaking change checklist)