-
Notifications
You must be signed in to change notification settings - Fork 1
[BB-10388] Additional Fixes #7
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
base: master
Are you sure you want to change the base?
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #7 +/- ##
==========================================
- Coverage 89.27% 89.19% -0.08%
==========================================
Files 10 10
Lines 289 361 +72
Branches 21 35 +14
==========================================
+ Hits 258 322 +64
- Misses 27 35 +8
Partials 4 4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
0a5a1f3 to
eb0ee2a
Compare
eb0ee2a to
b9800f1
Compare
| <div className="visually-hidden" role="status" aria-atomic="true" aria-label="Flashcard announcement"> | ||
| {announcementText} | ||
| </div> |
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 seems to work nicely for the most part. The only thing is for me the card front was not read when the card is first displayed after clicking the "start" button.
Also, I think stripping html from the announcement text goes against the client's QA recommendations too. Perhaps we can just follow the expected results and recommendations more closely here?
The content of the active flashcard side should be announced by screen readers when it becomes active. In addition, users should be informed whether the front or back side is currently displayed.
For this we can perhaps augment the existing aria-label on the card itself.
Use semantic HTML inside the card, such as
<h*>, <p>, and <strong>.
Dynamically update aria-hidden="true" for the inactive side, keeping the back side initially hidden.
You've already done this 👍
Use aria-live="polite" to announce the active card content to screen readers.
Maybe we can experiment with this on the card?
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.
The only thing is for me the card front was not read when the card is first displayed after clicking the "start" button.
Looks like SRs may not announce if the live region doesn’t get a detectable change at the right time. I’ve updated the implementation to clear the live region and then set it on the next tick so the first card is reliably announced after Start.
I think stripping html from the announcement text goes against the client's QA recommendations too
I don't think that should affect anything. Screen readers shouldn't announce HTML tags; only the accessible text. For the rest I have to admit, I don't know it well enough and mostly relied on recommendations/best practices I found online. Here are what I found:
aria-labelprovides an element’s accessible name (typically announced when the element receives focus); it’s not intended as a “change announcement” channel. So screen readers may not announce it it changes.aria-liveis the reliable mechanism for announcements of dynamically changing contents.role="status"is a live region with an implicitaria-live="polite"(ref)- Using a plain-text announcement is a common best practice to avoid overly verbose/odd output.
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 for the context! I don't know a heap about aria either.
Can we consider a method that puts the aria-live things on the card itself? So we don't need this extra work to manage state on a separate announcement section?
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 was my initial thought as well, but even with aria-hidden/inert on the inactive side, making the whole card live itself would mean any change to the injected HTML content, flip state, or index could trigger announcements of large chunks of content. If authors include lots of formatted text, the live region could get really noisy (This was one of the warning I found online as well).
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.
would mean any change to the injected HTML content, flip state, or index could trigger announcements of large chunks of content.
But any of these changes mean different content is displayed (eg. a new card, or now the back of the card), and thus should be announced by the screen reader. This is the same content that we're putting in the new announcement region anyway.
but even with aria-hidden/inert on the inactive side, making the whole card live itself...
What if we set the aria live for just the visible side of the card?
I really want to avoid this secondary live announcement area, as it's a lot of extra logic and state tracking, prone to bugs.
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’ve updated the implementation to clear the live region and then set it on the next tick so the first card is reliably announced after Start.
I just tested with a screen reader and unfortunately I'm not getting the first card announced still. :/
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.
But any of these changes mean different content is displayed (eg. a new card, or now the back of the card), and thus should be announced by the screen reader. This is the same content that we're putting in the new announcement region anyway.
Not exactly. If we set aria-live on .fc-card-front / .fc-card-back and leave the authored HTML inside, most screen readers will treat any DOM mutation inside that subtree as eligible for announcement. With rich content that can mean:
- reading more than you expect (or reading it twice: once as a live update, once because focus moved),
- weird ordering (e.g., it announces the “Flip” icon text / label / formatting artifacts),
- lots of chatter if any nested node changes.
I tried to make aria-live conditional tied to isFlipped like this:
- Front side:
aria-live={!isFlipped ? 'polite' : undefined} - Back side:
aria-live={isFlipped ? 'polite' : undefined}
And tested with VoiceOver (in macos with safari). But it didn't actually announce when flipped. On further investigation, I learned that some screen readers won’t announce just because aria-hidden toggled; they announce when the live region’s text content changes.
So in order to have reliable announcements, we need to either:
- force a real text change in that live region (same clear→set trick), or
- remount the live subtree on each change (e.g., changing a key), which is also logic, just a different kind.
Unfortunately we can't avoid the extra logic/state for this 🫤
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 just tested with a screen reader and unfortunately I'm not getting the first card announced still.
Just pushed a fix for it. Could you try again?
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.
If we set aria-live on .fc-card-front / .fc-card-back and leave the authored HTML inside,
Hmm I wonder if we can just have a card content section, and change the content depending on whether the back or front should be displayed? Rather than have both content in the dom at once.
Anyway, maybe we just need to run with what we have for now and investigate in the future if we find the logic hard to maintain.
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.
Just pushed a fix for it. Could you try again?
Doesn't appear to fix it sorry; it actually seems less reliable at reading the card content. :/
Also noting that the screenreader text is rather verbose. For example, on every card is read: "flashcard 1 of 2 click to flip button". And the announcement part starts with "flashcard announcement card 2 of 2". And these are combined when it successfully reads the announcement on a new card. Not sure how much of an issue it is though.
| styling: FlashcardStyling, | ||
| } | ||
|
|
||
| function htmlToText(html: string): string { |
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 don't think we should be stripping html for the screen reader; see next comment about the recommendations.
A note on testing: I couldn't get my redwood devstack working properly, so I tested on sumac. I don't think this will affect anything, just noting. |
48cd19a to
c898e66
Compare
dda1187 to
8957849
Compare
Description
This PR makes the following fixes:
Supporting Information
OpenCraft Internal Jira task: BB-10388
Testing Instructions
question/answertext