If You’re Inlining SVG Icons, How Do You Deal With Unique Titles and IDs?

Avatar of Chris Coyier
Chris Coyier on

Just inlining SVG seems to be the easiest and most flexible icon system. But that chunk of <svg> might have a <title>, and you might be appying IDs to both of those elements for various reasons.

One of those reasons might be because you just want an ID on the icon to uniquely identify it for JavaScript or styling purposes.

Another of those reasons is that for accessibility, it’s recommended you use aria-labelledby to connect the id and title, like:

<!-- aria-labelledby pointing to ID's of title and desc because some browsers incorrectly don't use them unless we do -->
<svg role="img" viewBox="0 0 100 100" aria-labelledby="unique-title-id unique-desc-id">

  <!-- title becomes the tooltip as well as what is read to assistive technology -->
  <!-- must be the first child! -->
  <title id="unique-title-id">Short Title (e.g. Add to Cart)</title>

  <!-- longer description if needed -->
  <desc id="unique-desc-id">A friendly looking cartoon cart icon with blinking eyes.</desc>

  <!-- all the SVG drawing stuff -->
  <path d="..." />
</svg>

But now you include that SVG somewhere twice. Say you’re in Rails…

<%= render "/icons/icon.svg.erb" %>

<p>yadda yadda yadda</p>

<%= render "/icons/icon.svg.erb" %>

Now you’ll have two elements on the page with the exact same ID, which is… bad?

It’s definitely bad if you’re relying on that ID for anything JavaScript related, because JavaScript will only find the first one and that might be confusing and weird.

I’m not entirely sure if it’s bad for accessibility. Perhaps someone else can weigh in there. Assuming the titles are the same, my guess is that it won’t matter much.

It’s bad for HTML semantics, I suppose, but I’m always kinda meh on that if there are no repercussions.

If you’re really interested in fixing this issue, my go-to would be to pass in the ID’s to be used manually.

Again if you were in Rails, you could pass locals:

<%=
  render(
    partial: "parts/modules/search",
    locals: {
      svg_id: "my-icon",
      title_id: "my-icon-title",
      desc_id: "my-icon-desc"
    }
  )
%>

And then design the icons to use those locals, like

<svg title="<%= svg_id %> aria-labelledby="<%= title_id %>" ... >
 
   <title id="<%= title_id %>>
  
   ...

</svg>

You could port that concept to any language. A React app could have:

<SVGIcon svg_id="..." title_id="..." />

A PHP app could set variables before an include:

$svg_id = "...";
$title_id = "...";
include("/icons/icon.svg.php");

Now it’s just on you to manage IDs to make them unique like we’ve always done with IDs.

This little post was inspired by Austin Wolf, who had this problem and thought through some solutions. This also included auto-generating unique IDs:

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

That also seems like a good solution to me.

I’d be interested to hear more thoughts!