question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItĀ collects links to all the places you might be looking at while hunting down a tough bug.

And, if youā€™re still stuck at the end, weā€™re happy to hop on a call to see how we can help out.

[Badge] Improve accessibility

See original GitHub issue
  • I have searched the issues of this repository and believe that this is not a duplicate.

Summary šŸ’”

It would be helpful to have a little more flexible control over both nodes used to compose the <Badge>, so the badge can display the correct UI for sighted users and also render a helpful label for assistive technology.

Examples šŸŒˆ

In my app we have a link in the primary nav that wraps badge wrapping an icon, used to indicate the total number of notifications for the current user.

Screen Shot 2020-08-04 at 5 51 30 PM

Demo: https://codesandbox.io/s/material-demo-cc7rw?file=/demo.js

const notificationsCount = 1000

<a href="/notifications">
  <Badge badgeContent={notificationsCount} color="primary">
    <MailIcon titleAccess="notifications" />
  </Badge>
</a>

But with the above markup the linkā€™s accessible name ā€” used when screen readers encounter the link, for example ā€” is

notifications 99+

Screen Shot 2020-08-02 at 11 20 31 PM

when it would ideally be

99+ notifications

Screen Shot 2020-08-02 at 11 21 14 PM

One option is to change the DOM order of these nodes and put the {children} after the <span>{displayValue}</span>. If itā€™s safe to assume that this is a logical DOM order for most users, and it doesnā€™t affect the visual layout, then that seems like a reasonable solution.

But I was hoping to have full props access to the <span>{displayValue}</span> node, so I could find another solution like hiding it from assistive technology using aria-hidden and moving the equivalent of displayValue to the accessible icon title. Itā€™s a little annoying that weā€™d have to recreate the logic of displayValue, but I could live with that.

Screen Shot 2020-08-04 at 6 04 41 PM

Demo: https://codesandbox.io/s/material-demo-3ghl7?file=/demo.js

const notificationsCount = 1000
const max = 99;
const displayValue = notificationsCount > max ? `${max}+` : notificationsCount;

<a href="/notifications">
  <Badge
    badgeContent={notificationsCount}
    color="primary"
    displayValueProps={{ "aria-hidden": true }}
  >
    <MailIcon titleAccess={`${displayValue} notifications`} />
  </Badge>
</a>

Unfortunately thatā€™s not part of the <Badge> API, so thatā€™s not possible. And using the classes prop wonā€™t help here, either, since thereā€™s no CSS that will hide a node from assistive technology and preserve it visually, only the opposite (e.g. display: none). So the resulting accessible label is

99+ notifications 99+

Screen Shot 2020-08-04 at 6 04 41 PM

The next option I tried was wrapping the badgeContent in an aria-hidden node directly, but that breaks some more default functionality, like passing in my own displayValue and specifiying that it should be hidden when the count is 0. If it were possible for the <Badge> component to read children as the equivalent of innerText and then parse it as an integer, then <span aria-hidden>8</span> could still be parsed as the number 8 instead of a string or a component, etc.

Screen Shot 2020-08-04 at 6 19 10 PM

Demo: https://codesandbox.io/s/material-demo-fxbpy?file=/demo.js

const notificationsCount = 1000
const max = 99;
const displayValue = notificationsCount > max ? `${max}+` : notificationsCount;

<a href="/notifications">
  <Badge
    badgeContent={<span aria-hidden>{displayValue}</span>}
    color="primary"
    invisible={notificationsCount === 0}
  >
    <MailIcon titleAccess={`${displayValue} notifications`} />
  </Badge>
</a>

Finally, it all works! But it seems unnecessarily painful to get there.

I recognize there are other options, still, like

Demo: https://codesandbox.io/s/material-demo-ycehq?file=/demo.js

const notificationsCount = 1000

<a href="/notifications">
  <Badge badgeContent={notificationsCount} color="primary">
    <MailIcon />
  </Badge>
  <span className="visually-hidden">notifications</span>
</a>

But either changing the default DOM order of the two nodes or providing props access to the displayValue both seem like reasonable enhancements, as well.

Motivation šŸ”¦

Iā€™d love to leverage of all the great existing logic and UI built into <Badge>, instead of re-writing big chunks of it to accomodate an accessible label.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:2
  • Comments:14 (10 by maintainers)

github_iconTop GitHub Comments

2reactions
andrewborsteincommented, Aug 6, 2020

Hey @eps1lon Iā€™m sorry if Iā€™ve come across wrong, or, on the flip side, if Iā€™m misinterpreting your responses. It feels like this conversation has gone astray somehow. I opened the issue with the understanding it wasnā€™t an obvious show-stopper with a clear solution. But I thought Iā€™d put it out there and that if the maintainers saw merit in some of the suggestions, thatā€™d be great! And if not, thatā€™s totally fine too.

Originally, the only suggestion I had written was that itā€™d be helpful (and seemingly on par for other MUI components) to spread props on the displayValue node, so the component had a tiny bit more flexibility for consumers like myself. But then when I saw the ā€œMotivationā€ section of the issue template, it seemed more useful to explain why I got to that conclusion in the first place ā€” describing the problem, not just one potential solution.

As I said earlier, I will absolutely understand if MUI doesnā€™t think this is worth tackling. Itā€™s not important to me to be right, I was just hoping to find opportunities to contribute to MUI. My teammates and I work with the framework everyday and would love to give back more where itā€™s helpful. So I would love start out on the right foot. šŸ™

In any case, Iā€™m still happy to answer your questions best as I understand them.


Comparison with what? Are you sure that the code you compare against is correct?

I donā€™t believe thereā€™s an objective ā€œcorrectā€ here when talking about strings that correspond to localized written language. If you were to ask me, ā€œHow many comments are there on this thing?ā€ I would say, ā€œ8 commentsā€ as opposed to ā€œcomments 8ā€. Thatā€™s not ā€œcorrectā€ per se, just more conventional, at least in English. So Iā€™m reading the accessible badge label from the same lens.

Iā€™m not sure how MUIā€™s approach to localization would affect this, but my assumption is that the DOM order in this component doesnā€™t change in different locales and that the default locale for the app is considered English. If those things are true, it doesnā€™t seem like a stretch to imagine that some particular formulation(s) of English phrases are more conventional than others and thus worth aiming for in MUIā€™s components. But I definitely donā€™t believe there is one ā€œcorrectā€ solution here, and if that makes it more challenging to find an agreeable solution thatā€™s totally fair.

I donā€™t think these patterns are generally good. Letting screen readers make these calls is almost always the better choince since they have better domain knowledge. It might be a configuration issue with the screen reader, or just a bug. In the end the first rule of aria should always be considered: donā€™t use aria.

I totally agree about the first rule of aria. And I agree that we should be deferring to AT as a rule of thumb about how to treat web content, that they should be considered the domain experts. But I think this particular case could be considered a real world shortcoming of AT thatā€™s worth acknowledging and working around. For example, NVDA ignores the plus and equals symbols. It says ā€œfive two sevenā€ when it should say ā€œfive plus two equals seven.ā€ They have clearly made that choice for some reason, but it may not align with this componentā€™s intent. Given that the screen reader is an entirely different medium and itā€™s my assumption that MUI is not building primarily for AT, the screen reader naturally has to make some assumptions on our behalf.

Itā€™s my understanding that the + character in the Badge label is intended to convey that there are more than 99 of something, or whatever the max number is. But for NVDA users (the most popular screen reader) it will always read ā€œ99ā€ even when the count is greater than ā€œ99ā€. Itā€™s obviously not intentional and annoying that we even have to think about it, but itā€™s a small way in which we could gain more parity between sighted and non-sighted users. I think letting all users know there are more than n of something seems to match the spirit of the +.

Iā€™m curious why you link a post title why ā€œaria-label is xenophobeā€ but then immediately suggest that reversing the order is correct (effectively saying that thereā€™s a single correct position for the badge content and direction a language is in). Are you sure this would be correct for every language and every position of the badge content?

Iā€™ll try my best to clarify my earlier statements. Iā€™m sorry if it came across this way, but I donā€™t mean to suggest thereā€™s a single ā€œcorrectā€ position or that changing the DOM order would create a conventionallly semantic label for all users in all locales.

But if (itā€™s a big if) MUI considers English the default locale, then [count] [things] seems more conventional, that more people might understand what it means. MUI doesnā€™t seem to be intentionally taking a stand about the accessible label by using a specific DOM order. But a given DOM order exists nonetheless, which creates accessible label by default. So if you agreed that the MUI default could better match the default locale of English, then maybe thatā€™d be worth pursuing. I recognize, though, that itā€™s subjective and might be safer to not take a stand at all and let individual consumers decide on accessible labels for themselves.

Why is aria-label not translateable?

Itā€™s manually translatable just like any string in a codebase, but some of the common automatic machine translation services (e.g. Google Translate) wonā€™t reliably translate that attribute. This is one example Adrian gives in his article, where the aria-label of Left-Pointing Magnifying Glass remains untranslated. So if there are more reliable alternatives like .visually-hidden label text, itā€™s nice to use them. Support for automatically translating aria-label has been improving, but itā€™s still not perfect. And I agree with you that the first rule of aria would apply here, too.

I donā€™t understand how this applies to React generally or my code specifically?

Itā€™s not a React problem or specifically related to the <Badge> component, just an issue with aria-label in general. I shared the links to explain why your suggestion about using aria-label text is totally valid (and appreciated!) but not applicable in my specific use case. Iā€™d like to be able to support automatic translation services in the app Iā€™m working in.

1reaction
eps1loncommented, Aug 27, 2020

So the idea is that you donā€™t handle translation at all but defer to google translate. And that approach does not work with certain naming techniques.

While I understand that concern I donā€™t see this as a viable restriction for us. aria-label is specified, implemented and used by authors. Are there any plans by the ARIA folks to remove this attribute since itā€™s not translateable and if not what reasons did they give? Especially considering aria-description is on track to become standardized as well. Seems like theyā€™re doubling down on problematic attributes.

Seems like

Allow any props to be spread on the {displayValue} node.

be the best approach but I would only start with id for now. That way you could do:

<a href="/notifications" aria-labelledby="display-node icon">
  <Badge badgeContent={notificationsCount} color="primary" displayNodeId="display-node">
    <MailIcon titleAccess="notifications" id="icon" />
  </Badge>
</a>

For the + vs plus issue a bit more research would be appreciated like existing issues, behavior in other screen readers etc. Because you can fix this right now manually with <Badge badgeContent={<React.Fragment>99<div aria-hidden>+</div><span className="visually-hidden">plus</span></React.Fragment>} />

Read more comments on GitHub >

github_iconTop Results From Across the Web

Exploring badge accessibility - usethis
A key point is that the badge often presents dynamic information. We'd like to improve the user experience for those consuming the README...
Read more >
Badges Related to Accessibility - Credly
Showing all badges for: Accessibility ... Accessibility in Higher Education: Accessibility's Legal Landscape ... Improving Your Online Course.
Read more >
Badges in Accessibility - Accessibility at Penn State
The badges are open to all Penn State staff, faculty and students and are designed to demonstrate proficiency in a particular accessibilty skill...
Read more >
[Badge] Improve accessibility #22070 - mui/material-ui - GitHub
Examples. In my app we have a link in the primary nav that wraps badge wrapping an icon, used to indicate the total...
Read more >
Website Badge & Accessibility Center Video Tutorial
Learn about the Accessible Web Website Badge and Accessibility Center. Activate it on your site in less than 5 minutes.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found