Icons as React Components
David Gilbertson
16219

Great article, David Gilbertson. I’ve been using this pattern of SVG icons as React components for a month or so now and love it! However, I’ve recently run into an accessibility issue.

Tl;dr

How do I ensure unique IDs (for accessibility labelling) on each icon when there may be many of the same icon rendered on one screen?

Problem

I’m using the aria-labelledby attribute on the SVG element linked to the id attribute on the title element in order to give screen readers an alternative name to each icon.

const Icon = ({ icon }) => (
<svg aria-labelledby={icon}>
<title id={icon}>{icon} icon</title>
// ...
</svg>
)

This worked for a while until recently when I needed to render a lot of the same icon on one page.

Let’s say I have an “Orders History” page, and need to render a bunch of past orders, where each order has some sort of rating, and the rating is composed of multiple star icons.

I noticed with the rendered output that I now have a bunch of elements with the same star ID! That’s no good. But how do I get around this?

Possible Solutions

Neither of the solutions listed below feel like the correct answer to me, but I’m struggling to find alternatives. Any input you have on how you’ve solved this accessibility issue would be very much appreciated!

Suffix all id attributes with a unique ID

One thought I had was to suffix the id with a uuid, which may render something like this

<svg aria-labelledby="star-6c84fb90-12c4-11e1-840d-7b25c5ee775a">
<title id="star-6c84fb90-12c4-11e1-840d-7b25c5ee775a">star icon</title>
// ...
</svg>

That doesn’t seem very friendly though. I imagine that screen readers would read out the entire ID name, which would just be a noun (star) followed by a bunch of garbled characters that aren’t relevant to the user.

Optional prop for icons that will be iterated upon

Another thought I had was to extend the <Icon /> API with some sort of optional prop that allows for indexing (similar to the reserved key prop in React when iterating over elements in an array).

const Icon = ({ icon, token }) => (
<svg aria-labelledby={`${icon}-${token}`}>
<title id={`${icon}-${token}`}>{icon} icon</title>
// ...
</svg>
)
// Later ...
;[...Array(5)].map((_, i) => <Icon icon='star' token={i} />)

Of course, this breaks down once you need to render multiple arrays of the same icon since the indexing will be reset. And adding more characters to the token to increase uniqueness just feels like an amateur approach to solution one above.

Conclusion

I’m not entirely sure how to handle this accessibility concern with the <Icon /> component. Through my research, I haven’t found a ton of useful information on what is acceptable and what is not (e.g. is it okay to use the uuid solution?).

Any advice someone more experienced with web accessibility would be willing to give on this topic would be super helpful.

Show your support

Clapping shows how much you appreciated Austin Wood’s story.