Graphics used as links and buttons need accessible names

Applicable Role(s): Content Creator, Developer

Overview

User interface (UI) elements like links and buttons are critical in telling a user what will happen if the element is selected. If the element just uses an icon as the link without a text alternative, someone using assistive tech may not know where they will end up when clicking it, or what command to give the computer to make the feature work.

Some icons may not also be as intuitive to users from different cultures, or who aren't visually-oriented learners.

Best Practices

There are important considerations for active images, icon fonts, and scalable vector graphics (SVGs).

Images

If it's an image <img> element, the text can be provided with the alt attribute (See include alt text on images).

The alt text should describe the purpose of the control, rather than the image itself. Example: a print button with a printer graphic should have alt text of "Print document" rather than "printer icon."

Icon fonts and SVGs

If it's an icon font or SVG within a link or button, the button/link markup should do one of the following:

  • Provide both the icon and text together, with the icon being decorative by setting aria-hidden="true" on it.
  • Visually hide the meaningful text, but also setting the graphic to aria-hidden="true".
  • Give the icon an aria-label to provide a meaningful name if real text can't be included in the link or button

If the link or button is an SVG, then the SVG's role attribute should be set to the proper element and given a name through aria-labelledby (see Name SVGs with proper semantics)

If the SVG is intended to be a button or link, a user should be able to use the Enter and/or Space bar as necessary to activate the SVG just like a mouse could.

Pattern Examples

A Common Inaccessible Example: Social Media

Series of social media links using Font Awesome icons
Version 1
<a class="..." href="#">
  <span class="fab fa-twitter"></span> 
  // Twitter icon
</a>
Version 2
// HTML
<a class="..." href="#"> 
  <span class="fab fa-twitter">
    ::before
  </span>  
</a>

// CSS, content renders icon
.fa-twitter:before {
  content: "\f099";
}

Why Don't These Examples Work?

In version 1, this icon doesn't have any meaningful text between the <a> or <span> tags, so the purpose of the link will not get conveyed properly in screen reader technology and just be announced as "link."

Because there is no name for the link, if someone needs to vocalize commands through speech recognition software and says "Click the Twitter link," nothing would happen because no link with the name "Twitter" exists in the page.

With version 2, the content tends to get conveyed, but may not announce correctly to users. Instead of hearing it's a Twitter link, they may hear a random word like "exclaim" or a random string of letters and numbers. 

Either way, the purpose of the link will not be clear to users that use assistive technology to go through your content.

Better Example: Social Media

The link contains a visually-hidden span of text that provides the name of the link, but doesn't show the text by default. The SVG also has aria-hidden="true" because the icon is more redundant to the link text.

<a href="#" class="social-icon twitter">
<span class="visually-hidden">
   Western on Twitter
  </span>
  <svg aria-hidden="true" ...>
  <!-- SVG stuff --> 
  </svg>
</a>

Better Example: Search Button

<button>
<span class="visually-hidden">Search</span>
<span class="material-icons" 
aria-hidden="true">search</button>
</button>

Even Better Example: Contact Info

This example includes both the icon and the text, so the user doesn't have to rely on knowing what the icon means to understand what will happen. The link text is also translatable, so it should translate correctly for international users.


<a href="#" class="icon-with-text blue-bg">
 <span class="material-icons" 
  aria-hidden="true">
   home
 </span>
 <span class="icon-text">
   Home
 </span>
</a>

<a href="#" class="icon-with-text blue-bg">
 <span class="material-icons" 
  aria-hidden="true">
   mail
 </span>
 <span class="icon-text">
   Email
 </span>
</a>

Home Email