[a11y] Fix reporting flyout screenreader issues#220028
[a11y] Fix reporting flyout screenreader issues#220028paulinashakirova wants to merge 6 commits intoelastic:mainfrom
Conversation
|
Pinging @elastic/kibana-accessibility (Project:Accessibility) |
| </EuiText> | ||
| </EuiFlyoutHeader> | ||
| <EuiFlyoutBody banner={outcomeCallout}> | ||
| <EuiFlyoutBody banner={outcomeCallout} aria-live="polite"> |
There was a problem hiding this comment.
What if we move the aria-live attribute to the content of outcomeCallout? Could you also try just setting role="status" for EuiCallOut?
There was a problem hiding this comment.
Thank you for these ideas 💡
I tested them 😊
Setting role="status" and/or aria-live="polite" on EuiCallOut without anything set on EuiFlyoutBody didn't work in Safari, Chrome and Firefox.
My assumption it is because we are rendering Callout conditionally so VO doesn't read the content that appears later on in the DOM.
I understand the implication that if we add aria-live for the whole flyout, in case in the future we have more "appearing" things, screenreader will be reading all of them, but in our current case, this callout is the only element that needs to be read dynamically.
What do you think I should do?
I am not sure I have other ideas for now, but I can keep looking 👀 😊
Or we could keep this fix as it is now as an option.
There was a problem hiding this comment.
Right, but my suggestion here aims to address that issue globally. What if we move the fix to the EUI side and implement something like this:
@elastic/eui-team, would a fix like this be acceptable?
There was a problem hiding this comment.
@alexwizp this solution is simple enough and would indeed allow to define the live region directly on the banner as opposed to the whole flyout. The live region node would always be in the DOM, and screen readers would be able to detect the content change inside.
My only concern is that this way we will always render a div, there will be a redundant DOM node for every flyout that gets rendered. Furthermore, it's styled, which could affect visually the rest of the flyout content.
From my perspective, the trade-off is worth it to make the design accessible.
One note, we should try to optimize for NVDA and JAWS. It's worth testing the behavior with them. If you need any help with that, I'm more than happy to assist!
There was a problem hiding this comment.
@alexwizp and @weronikaolejniczak 😊
Thank you for your suggestions/discussion.
I was thinking now - and came up with 2 other ideas... what if we wrap the callout in a div (it is already used this way in group_name.tsx and flash_messages.tsx
<EuiScreenReaderOnly>
<div aria-live="polite" role="status">
{a11yAnnouncement}
</div>
</EuiScreenReaderOnly>
return (
<div aria-live="polite" data-test-subj="FlashMessages">
{messages.map(({ type, message, description, iconType }, index) => (
<Fragment key={index}>
<EuiCallOut
color={FLASH_MESSAGE_TYPES[type].color}
iconType={iconType ?? FLASH_MESSAGE_TYPES[type].iconType}
title={message}
>
because not all callouts need to be announced, right? Some are static information without a dynamic update.
Or...
For example add an optional prop announceChanges or asStatus, to avoid "overannouncing"...
The first option is faster since we don't need to involve Eui team, but if it could be beneficial for the future - we could proceed with discussing in eui channel...
wdyt?
There was a problem hiding this comment.
@alexwizp The downside of adding the banner like this is that it would read any content on update, meaning potentially unwanted content. EuiCallOut for example can have an optional close button or in theory any custom content as children.
toggle screenshot
Beyond that my concern is that it's not addressing the issue generically enough. It would kind of solve the issue in flyouts but not for any other usages of EuiCallOut (or other announcements) in other, similar places. Imho, we could try to solve this on a more generic level which would then also provide a solution for this specific use case in flyouts.
I've created a rough PoC here, to visualize the idea to:
- enhance
EuiScreenReaderLiveto support announcing updates on mount as well by updating the content initially and triggering a re-render (this allows us to work around the limitation of the live region having to be in the DOM already) - update
EuiCallOutwithEuiScreenReaderLiveto support screen reader output of its main content (leaving out unwanted content)
This then results in a usage inside EuiFlyout that resolves the original issue:
toggle screen recording
Screen.Recording.2025-06-20.at.19.03.04.mov
There was a problem hiding this comment.
@mgadewoll I agree with your approach overall, but I do have one concern: it may be difficult to ensure that EUI users — especially when using EuiFlyoutBody — remember to set disableScreenReaderOutput. Additionally, in most of our similar components, the default value for disableScreenReaderOutput is false, whereas here it's set to true. This change implies that screen reader output is disabled by default, which could be misleading. It might be worth considering a rename to better reflect this behavior.
As for EuiScreenReaderLiveProps, introducing both type and usePortal as separate props could lead to confusion. Would it be possible to simplify this by combining them into a single, more intuitive prop?
There was a problem hiding this comment.
@alexwizp That's a valid concern. And the choices are mainly due to it being a quick PoC and me trying to be careful about the impact. 😅
The reason I chose to use disableScreenReaderOutput={true}as default is to prevent potentially interfering with current implementations. EuiCallOut is used in many different places/ways and I don't have an overview of where additional announcements on mount might be an issue. 🤔
As for
EuiScreenReaderLiveProps, introducing bothtypeandusePortalas separate props could lead to confusion. Would it be possible to simplify this by combining them into a single, more intuitive prop?
Sure, the API is not finalized. I agree that type is not the most descriptive to what it's doing. What I tried here was to see what variants might be needed first. usePortal most likely can be removed as it's probably always needed to ensure the announcement content is not added next to the visual representation content. Otherwise we'd have duplicate content for screen reader users.
There was a problem hiding this comment.
@mgadewoll Thank you so much for all your help! 🤩
The fix you are proposing looks great!
I will happily wait for the fix on your end when you come to an alignment and will find time to implement it.
I will try to keep an eye on the issue, and if you could tag me or @alexwizp when your PR is in review - would be great 😌
And when you create an issue, could you please mention it here, so I could reference it. 🙏🏻
There was a problem hiding this comment.
@paulinashakirova Yes sure, will do! I added an issue on our side for it and we'll refine it on EUI side.
💚 Build Succeeded
Metrics [docs]Async chunks
History
|
|
🤖 Jobs for this PR can be triggered through checkboxes. 🚧
ℹ️ To trigger the CI, please tick the checkbox below 👇
|
|
Closed this PR because the fix will be done on EUI side. |
|
The issue is fixed. Can't reproduce anymore |
Summary
This PR fixes [Platform:StackManagement:AlertsandInsights:Reporting] Results of check browser are not announced and fixes [Platform:StackManagement:AlertsandInsights:Reporting] Run screenshot diagnostics panel announced incorrectly issues.
Screen.Recording.2025-05-04.at.15.34.04.mov