If it goes somewhere, it’s <a>
link.
When the user clicks a link, they are taken to a different location in the site.
Either another page or even another area of the same page
A link can look like a big shiny button but it must be coded as <a>
link
Buttons cause an action to occur on the same page
Submit a form (even when submission takes you to a new page)
Open a menu
Launch a modal
Expand details
A button can look like a link, but it must be coded as a <button>
Code examples
Use semantic HTML with common sense names
This semantic HTML contains all accessibility features by default.
<a href= "/about/" >
About
</a>
About
Name links logically
Do not use a heading with a generic link below.
Instead, make the heading a link or programmatically associate the link with the heading using aria-describedby
.
<h3> About our coffee subscriptions</h3>
<p> Get the best coffee delivered to your door</p>
<a href= "/about/" >
Learn more
</div>
<h3><a href= "/about/" > About our coffee subscriptions</a></h3>
<p> Get the best coffee delivered to your door</p>
<h3 id= "unique-id" > About our coffee subscriptions</h3>
<p> Get the best coffee delivered to your door</p>
<a href= "/about/" aria-describedby= "unique-id" >
Learn more
</div>
Making a link with no href
focusable
Do not put anything but a URI in the href
A link with no href
will not be focusable with the keyboard without tabindex="0"
.
Add role="link"
to ensure screen reader reads the role
<a tabindex= "0" role= "link" >
About
</a>
About
Avoid custom elements
This custom button requires extra attributes and keyboard event listeners.
<custom-element role= "link" tabindex= "0" >
About
</custom-element>
Repeating text links
Sometimes the design will call for multiple links with the same text label. In a case like this, aria-label
can be used to name each link’s purpose.
<button> Get free coffee</button>
<a href= "/free-coffee-tc/" aria-label= "Free coffee terms and conditions" >
Terms & Conditions
</a>
<button> Get free donuts</button>
<a href= "/free-donuts-tc/" aria-label= "Free donuts terms and conditions" >
Terms & Conditions
</a>
Don’t duplicate the visible text name in the aria-label
Do not repeat the inner text content of a link in the aria-label
.
<a href= "/do-NOT-repeat-yourself/"
aria-label= "Do NOT repeat yourself" >
Do not repeat yourself
</div>
Don’t use javascript in href
Do not use "href="javascript:void(0)"
.
When screen readers read the href, it becomes confusing and nonsensical
<a href= "javascript:void(0)" >
Do not use javascript in href
</div>
Don’t use “#” in href
<a href= "#" >
Do not use # to populate the href
</div>
Disabled links
If it’s unavoidable to have a disabled link present you’ll need these attributes for the screen reader.
<a tabindex= "0" role= "link" aria-disabled= "true" >
Continue
</a>
Complex examples
Product Card with multiple controls
This example demonstrates an approach taken for when the card may have multiple controls within it.
Save $400 with offer
Sunset Red
Golden Canyon
Blue
Graphite
Monthly
$22.00,
Original price:
$50.00
For 36 months
Today
$0
down + tax
Full price $1,789,
Original price:
$1,998
Product Card as a single link
This card is a single link and does not consist of any other nested controls. Use of aria-labelledby
and aria-describedby
to control how the card is announced by screen readers.
<h2 class= "h-bravo" > Product Card with multiple controls</h2>
<p> This example demonstrates an approach taken for when the card may have multiple controls within it.</p>
<div class= "product-list multiple-controls" >
<div class= "product-list-item" >
<div class= "offer-container" >
<button type= "button" class= "tertiary" aria-label= "Save $400 with offer for mPhone Universe Max Extra Phabulous" >
Save $400 with offer
</button>
</div>
<div class= "link-container" >
<!-- The link DOES NOT wrap the entire description -->
<h3 class= "product-heading" >
<a class= "product-link" href= "/demos/" >
<span class= "brand" >
mPhone
</span>
<span class= "product-title" >
Universe Max Extra Phabulous
</span>
</a>
</h3>
<div class= "product-image-container" >
<img class= "product-image" src= "/assets/images/products/mobile-phone.png" alt= "mPhone Universe Max Extra Phabulous" />
</div>
<ul id= "meta" class= "product-meta" >
<li class= "rating" > 4.8 Stars</li>
<li class= "network" > 7G <span class= "hidden" > network compatibility</span></li>
</ul>
<div class= "end-cap" >
<ul id= "colors" class= "product-colors" >
<li class= "red" ><span class= "hidden" > Sunset Red</span></li>
<li class= "gold" ><span class= "hidden" > Golden Canyon</span></li>
<li class= "blue" ><span class= "hidden" > Blue</span></li>
<li class= "gray" ><span class= "hidden" > Graphite</span></li>
</ul>
<ul id= "pricing" class= "product-pricing" >
<li class= "monthly" >
<div><strong> Monthly</strong></div>
<strong>
$22.00<span class= "hidden" > ,</span>
</strong>
<span class= "hidden" >
Original price:
</span>
<s> $50.00</s>
<div> For 36 months</div>
</li>
<li class= "today" >
<div><strong> Today</strong></div>
$0
<div> down + tax</div>
</li>
<li class= "full-price" >
<strong> Full price</strong> $1,789<span class= "hidden" > ,</span>
<span class= "hidden" >
Original price:
</span>
<s> $1,998</s>
</li>
</ul>
</div>
</div>
</div>
</div>
<h2 class= "h-bravo" > Product Card as a single link</h2>
<p> This card is a single link and does not consist of any other nested controls. Use of <code> aria-labelledby</code> and <code> aria-describedby</code> to control how the card is announced by screen readers.</p>
<div class= "product-list big-links" >
<div class= "product-list-item" >
<a href= "/demos/"
aria-labelledby= "prod-0-eyebrow prod-0-name"
aria-describedby= "prod-0-meta-rating prod-0-meta-network prod-0-colors product-0-price-monthly product-0-price-today product-0-price-full" >
<div class= "offer-container" >
<svg style= "display: inline-block;" role= "img" aria-label= "Promo" xmlns= "http://www.w3.org/2000/svg" height= "1em" viewBox= "0 0 448 512" ><path d= "M0 80V229.5c0 17 6.7 33.3 18.7 45.3l176 176c25 25 65.5 25 90.5 0L418.7 317.3c25-25 25-65.5 0-90.5l-176-176c-12-12-28.3-18.7-45.3-18.7H48C21.5 32 0 53.5 0 80zm112 32a32 32 0 1 1 0 64 32 32 0 1 1 0-64z" /></svg> 15% off your next order
</div>
<div class= "link-container" >
<h3 class= "product-heading" >
<span class= "brand" id= "prod-0-eyebrow" >
mPhone
</span>
<span class= "product-title" id= "prod-0-name" >
Universe Max Extra Phabulous
</span>
</h3>
<div class= "product-image-container" >
<img class= "product-image" src= "/assets/images/products/mobile-phone.png" alt= "" />
</div>
<ul id= "meta" class= "product-meta" >
<li class= "rating" id= "prod-0-meta-rating" > 4.8 Stars</li>
<li class= "network" id= "prod-0-meta-network" > 7G <span class= "hidden" > network compatibility</span></li>
</ul>
<div class= "end-cap" >
<span id= "prod-0-colors" class= "hidden" > Four colors available</span>
<!-- hide colors - use visually hidden text x colors avialable -->
<!-- reduces verbosity and all colors are available on PDP -->
<ul id= "colors" class= "product-colors" aria-hidden= "true" >
<li class= "red" ></li>
<li class= "gold" ></li>
<li class= "blue" ></li>
<li class= "gray" ></li>
</ul>
<ul id= "pricing" class= "product-pricing" >
<li class= "monthly" id= "product-0-price-monthly" >
<div><strong> Monthly</strong></div>
<strong>
$22.00<span class= "hidden" > ,</span>
</strong>
<span class= "hidden" >
Original price:
</span>
<s> $50.00</s>
<div> For 36 months</div>
</li>
<li class= "today" id= "product-0-price-today" >
<div><strong> Today</strong></div>
$0
<div> down + tax</div>
</li>
<li class= "full-price" id= "product-0-price-full" >
<strong> Full price</strong> $1,789<span class= "hidden" > ,</span>
<span class= "hidden" >
Original price:
</span>
<s> $1,998</s>
</li>
</ul>
</div>
</div>
</a>
</div>
</div>
Further Reading