Make icons screen reader and assistive technology friendly for an inclusive web experience
Distinguishing icon semantic roles is the first step in accessibility:
| Type | Definition | Example | Accessibility Handling |
|---|---|---|---|
| Decorative | Pure visual decoration, conveys no information | Bullet icons before list items, decorative dividers | Use aria-hidden="true" |
| Functional | Conveys action, status, or information | Shopping cart icon, search button, error prompt | Add aria-label or sr-only text |
Decorative icons are purely visual and should be hidden from assistive technology
<!-- Correct: decorative icon hidden with aria-hidden -->
<i class="fa-solid fa-star" aria-hidden="true"></i>
<!-- Error: screen reader will read fa-star Unicode character -->
<i class="fa-solid fa-star"></i>
<!-- Decorative icons before list items -->
<ul class="list-unstyled">
<li><i class="fa-solid fa-check text-success" aria-hidden="true"></i> Completed</li>
<li><i class="fa-solid fa-circle text-muted" aria-hidden="true"></i> Pending</li>
</ul>When the icon itself is the interactive element or the unique identifier of a button:
<!-- Correct: button has text label, icon is decorative -->
<button class="btn btn-primary">
<i class="fa-solid fa-cart-shopping" aria-hidden="true"></i> Add to Cart
</button>
<!-- Correct: icon button uses aria-label -->
<button class="btn btn-link" aria-label="Search">
<i class="fa-solid fa-magnifying-glass" aria-hidden="true"></i>
</button>
<!-- Error: icon button has no accessible name -->
<button class="btn btn-link">
<i class="fa-solid fa-magnifying-glass"></i>
</button>SVG framework automatically includes role="img" and aria-labelledby for better accessibility
<!-- React: provide accessible text via title prop -->
<FontAwesomeIcon icon={faUser} title="User Info" />
<!-- Generated SVG automatically includes role="img" and aria-labelledby -->
<!-- <svg role="img" aria-labelledby="svg-title-1">...</svg> -->
<!-- Decorative icon -->
<FontAwesomeIcon icon={faStar} aria-hidden="true" />
<!-- Vue: use title or aria-label prop -->
<font-awesome-icon :icon="['fas', 'user']" title="User Info" />
<font-awesome-icon :icon="['fas', 'star']" aria-hidden="true" />Provide extra context with the title attribute
<!-- Use title attribute (shown on hover) -->
<i class="fa-solid fa-circle-info" aria-hidden="true"
title="Learn More"></i>
<!-- Use sr-only class (visually hidden but readable) -->
<span class="fa-layers">
<i class="fa-solid fa-circle" style="color: #0d6efd;" aria-hidden="true"></i>
<i class="fa-solid fa-check" style="color: white;" aria-hidden="true"></i>
<span class="sr-only">Verified</span>
</span>Brand icons (fa-brands) may have additional trademark restrictions
<!-- Brand icons need to communicate trademark role: -->
<a href="https://twitter.com" target="_blank" rel="external nofollow" aria-label="Follow us on Twitter">
<i class="fa-brands fa-x-twitter" aria-hidden="true"></i>
</a>
<!-- Social media link list -->
<div class="social-links">
<a href="https://github.com/example" aria-label="GitHub">
<i class="fa-brands fa-github" aria-hidden="true"></i>
</a>
<a href="https://weibo.com/example" aria-label="Weibo">
<i class="fa-brands fa-weibo" aria-hidden="true"></i>
</a>
</div>Only non-decorative icons need accessibility text; decorative icons should use aria-hidden
aria-hidden only hides from screen readers; the icon is still visible on screen