• 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>
About
  • 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>
  • 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>

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 &amp; Conditions
</a>
<button>Get free donuts</button>
<a href="/free-donuts-tc/" aria-label="Free donuts terms and conditions">
  Terms &amp; 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>
  • 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.

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