-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Aria Live Configuration #4414
Aria Live Configuration #4414
Conversation
🦋 Changeset detectedLatest commit: f4aaf24 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit f4aaf24:
|
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 like the direction this is headed! I haven't done a thorough review of Select.js
yet, but I thought I should provide some initial comments. Sorry it took so long for me to take a look!
const isSelected = !!( | ||
focusedOption && | ||
selectValue && | ||
selectValue.includes(focusedOption) |
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.
this fails to determine isSelected
if isMulti
and multiple options are chosen. I tried importing ../internal/react-fast-compare
(which doesn't appear to be used anywhere) and made it work; for your consideration:
selectValue.includes(focusedOption) | |
!!selectValue.find((selected) => exportedEqual(selected, focusedOption)) |
that function imported at the top:
import exportedEqual from '../internal/react-fast-compare';
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.
Thanks, let me take a look at this and add some tests to make sure this doesn't get missed.
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.
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 do have latest. I don't know how to provide a good example, but I'll try. I'm using hooks:
const FRUITS_AND_VEGGIES = [
'Apple',
'Artichoke',
'Asparagus',
'Banana',
'Beets',
'Bell pepper',
'Broccoli',
'Brussels sprout',
]
export const MultipleValues = () => {
const options = FRUITS_AND_VEGGIES.map((x, i) => ({
value: x,
label: x,
isDisabled: i % 5 === 1,
}));
const [value, setValue] = useState<any>(options[2]);
return (
<div>
<label id="ex3-label">Fruits and Vegetables</label>
<Select
isMulti
value={value}
onChange={(v) => setValue(v)}
options={options}
closeMenuOnSelect={false}
aria-labelledby="ex3-label"
isSearchable
isClearable={false}
/>
</div>
);
};
Here's what I'm getting:
But it's a different message initially:
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.
Oh, you know what's happening is that the function is being rerendered, and the array map is generating new objects (in my example). So your test is checking for identical objects, which fails in my case. If I defined it outside of my function component, then it should work with the simple equality check. Makes sense. For your consideration.
I could even put the array in a useMemo hook. But maybe it would be important to know that for this case. Not sure.
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.
There is some internal discussion regarding the conversation of comparing objects by value or reference. I don't disagree with a value based approach over one that is referential, but opted to remain consistent with the existing approach for the sake of consistency.
@bozdoz , so I reworked a few things about this component over the last week.
|
</span> | ||
<span id="aria-context"> {this.constructAriaLiveMessage()}</span> | ||
</A11yText> | ||
<LiveRegion |
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.
Low effort improvement would be to include this in getComponents
:
In Select.js
const { LiveRegion } = this.getComponents()
And then for components/index.js:
LiveRegion: ComponentType<LiveRegionProps>,
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 exposing it in the public facing components is a near future goal but not for this release based on a few reasons:
- It's not completely known how well this works with all screen readers yet.
- The logic to recreate the LiveRegion given the amount of dependencies isn't trivial.
- React-select does exist as something designed to be customizable, but we want to be cautious given that this can very negatively affect usability for those reliant on a11y assistive technology.
- There are still a few aria-live issues to be discussed and solved before exposing the api as incomplete and potentially in need of changing.
I think ultimately I envision all of the derived messages would be passed as props to the LiveRegion making it easier to customize in as many different a11yText sections as desired.
WIP: recreation of Kashkovsky support intl a11y
Original PR: #3550
Revised PR: #4161
First pass: #4390
Documentation PR: #4203
Purpose
The purpose of this PR is to allow the aria live messages to be customized to support internationalization or serve to provide more context to assistive technologies #3352
Proposal
prop:
AriaLiveMessages
is an object supporting several formatting functions for various aria-live messages and eventsAdditionally: a new prop
aria-live
is introduced to allow users to change the voice of the aria-live component. This should satisfy users unhappy with passive voice (due to listbox guidance interfering with focus events) and users who want to implement a solution without any aria-live.This PR also introduces a new
LiveRegion
component thought it is not yet shared publicly. As relevant state changes are made in Select.js, they are passed as props to LiveRegion and then useuseEffect
hooks to determine what changes should be made to the rendered aria live messaging, This also has the benefit of removing 100+ lines of code from Select.jsWhile several other aria-live issues exist, this one is comprehensive enough to test first and then isolate other issues in a follow up. I will keep the to-dos below to keep visibility.
Additional Findings
Allow aria-live and role to be configurable
Concerns
screenreaderStatus
prop return the number of focusableOptionsGroups
formatGroupHeader
as a formatting function and creating a new bulitin calledgetGroupHeaderLabel
.Aria-live TODOs
and...