Links vs buttons
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
If it does something, it’s a <button>
- 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>
Name links logically
- Do not use a heading with a generic link below.
- Instead, make the heading a link.
<h3>About our coffee subscriptions</h3>
<p>Get the best coffee delivered to your door</p>
<a href="/about/">
Learn more
</div>
Making a link with no href
focusable
If a link has no definable url, add tabindex="0"
to make it focusable.
- A link with no
href
will not be focusable with the keyboard. - Do not put anything but a URI in the
href
<a tabindex="0">
About
</a>
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>
Complex examples
- Don’t wrap large blocks of content or nest other interactive components inside a link.
- This complex example uses a simple link and references product information using
aria-describedby
- This allows the link to be read first (without the repetition of the image alt text) and then the screen reader will read the related product information (colors, pricing).
- The HTML is written in logical order for the screen reader and CSS grid layout is used to re-arrange the elements visually.
- No Javascript is used, this example uses well supported CSS only techniques
Shop phones
-
mPhone Universe Max Extra Phabulous
- Sunset Red
- Golden Canyon
- Blue
- Graphite
-
Monthly$22.00, Original price:
$50.00For 36 months -
Today$0down + tax
-
Full price $1,789,
Original price:
$1,998
-
mPhone Universe Max Sorta Phabulous
- Sunset Red
- Golden Canyon
- Blue
- Graphite
-
Monthly$22.00, Original price:
$50.00For 36 months -
Today$0down + tax
-
Full price $1,789,
Original price:
$1,998
-
mPhone Universe Not So Phabulous
- Sunset Red
- Golden Canyon
- Blue
- Graphite
-
Monthly$22.00, Original price:
$50.00For 36 months -
Today$0down + tax
-
Full price $1,789,
Original price:
$1,998
<h2 class="h-bravo">Shop phones</h2>
<ul class="product-list">
<li 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>
<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 class="button" aria-hidden="true">
See details
</div>
</div>
</li>
<li class="product-list-item">
<div class="offer-container"></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 Sorta Phabulous
</span>
</a>
</h3>
<div class="product-image-container">
<img class="product-image" src="/assets/images/products/mobile-phone.png" alt="mPhone Universe Max Sorta Phabulous"/>
</div>
<ul id="meta" class="product-meta">
<li class="rating">4.8 Stars</li>
<li class="network">6G <span class="hidden">network compatibility</span></li>
</ul>
<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 class="button" aria-hidden="true">
See details
</div>
</div>
</li>
<li class="product-list-item">
<div class="product-group-container" role="group" aria-label="Phone">
<div class="offer-container">
<button type="button" class="tertiary" aria-label="Save $400 with offer for mPhone Universe Not So Phabulous">
Save $100 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 Not So Phabulous
</span>
</a>
</h3>
<div class="product-image-container">
<img class="product-image" src="/assets/images/products/mobile-phone.png" alt="mPhone Universe Not So Phabulous"/>
</div>
<ul id="meta" class="product-meta">
<li class="rating">4.8 Stars</li>
<li class="network">2G <span class="hidden">network compatibility</span></li>
</ul>
<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 class="button" aria-hidden="true">
See details
</div>
</div>
</div>
</li>
</ul>