Skip to content
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

Using the icon name for id/aria-labelledby has a high risk for duplicate ids #2

Open
fvsch opened this issue Mar 19, 2018 · 2 comments

Comments

@fvsch
Copy link

fvsch commented Mar 19, 2018

Hi, and sorry for the lengthy bug. :P

The id/aria-labelledby pattern used for the icon components can be useful for VoiceOver support (other screen readers should manage to read the <title> without it), but it’s a difficult technique because it requires unique ids and there’s a risk of duplicate ids in the document. So using the icon name only is a bit risky.

  1. If this name is generic, e.g. menu, it may already be used in the page, and adding an element with this id before the “real” target using that id may break existing functionality (e.g. <a href="#menu">Skip to navigation</a> might point to an icon and not to the menu somewhere else in the page, <label for="user">User name</label> may point to an icon and not the relevant input, etc.).

  2. If an icon is used several times (e.g. in a loop), the document will have duplicate ids and it’s unclear if aria-labelledby will work correctly in this case.

It might be safer to generate a unique id, for instance:

// only once at instantiation, not sure if that should be a computed property in Vue
const id = 'icon-' + iconName + '-' + Math.floor(Math.random() * 1000000) // e.g. "icon-arrow-764820"

Do you think this could be included in your examples in some way?

On a related topic, in my experience using a technical name (e.g. an icon id derived from a file name) is not satisfying alternative text: the icon name may be different from the meaning we’re trying to convey, and when we start localizing the site it’s even more unhelpful (e.g. a Spanish speaker would be lost with a button whose label is "looking-glass icon").

I’ve used two different solutions in the past:

  1. Pass a different prop/parameter explicitly for the alt text (a prop named alt could make sense). Then in the icon component or template I only output the <title id="…">…</title> and aria-labelledby attribute if alt text is provided.
  2. Or avoid alt text on <svg> icons altogether, and:
    • for "icon + visible label" patterns, do nothing;
    • for icon-only buttons and links, use <a aria-label="…">…</a> and <button aria-label="…">…</button>, which has less flaky support in screen readers.

Because of the technical difficulty and footgun of duplicate ids I tend to go with the second solution, but both are okay.

@sdras
Copy link
Owner

sdras commented Mar 20, 2018

Hi and thanks for visiting,
I can get behind using the unique IDs but let me first talk to some people with vision impairments to see what they think of having numbers called out to them along with the title. I don't think I'd include that in every icon but it does sound like it would be good to have an example section for the use case you're talking about.

The second piece of this is addressed by the lang="en" that's on the icon- if the screenreader is translating to spanish, it will be translated.

@fvsch
Copy link
Author

fvsch commented Mar 20, 2018

For the numeric id, I was suggesting using it for the id and aria-labelledby attributes only, not as human-readable content. So, using a distinct computed property, the template fragment for that might be:

<svg … :aria-labelledby="labelId">
  <title :id="labelId" lang="en">{{iconName}} icon</title>
  …
</svg>

The second piece of this is addressed by the lang="en" that's on the icon- if the screenreader is translating to spanish, it will be translated.

I’m not sure. I don’t think screen readers that translate content are common, and if some have this feature I wonder if it works on the DOM and not only by translating the initial HTML. I’m more used to localized app where the application code itself inserts localized strings (contributed by humans) when rendering the HTML or DOM. Things like:

<Icon name="cross" :alt="i18n.t('close')" />

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants