A11Y Solutions
Provides auto-suggestions when entering text

    Buttons & Links

    It's very easy to lose implicit semantic meaning of buttons and links, or to forget to provide it for other elements that need to be interactive.

    The Problem

    Expected keyboard controls and screen reader output are omitted without proper semantics.

    The Solution

    Ensure semantic meaning is provided in cases where it is not implicit. Four examples below.

    Related Articles

    Live Examples

    Before illustrates the problem, After illustrates the solution. Click the header to see it larger in a modal.

    Please note that this Before example contains inaccessible code, use this link to skip to the After Live Example



    Code Comparison

    Code diff between the before and after examples above to show the changes necessary. To copy the final source click on the 'after' path link before the diff.


    Comparing /examples/semantics/buttons-and-links/before/index.html to /examples/semantics/buttons-and-links/after/index.html

    <!DOCTYPE html>
    <html lang="en">
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Accessibility Solutions - Semantics - Buttons and Links</title>
    <link rel="stylesheet" href="../../../presentation.css" />
    <link rel="stylesheet" href="buttons-and-links.css" />
    <h1>Buttons and Links examples</h1>
    <h2>Implicit Semantic Meaning</h2>
    We lose implicit semantic meaning when using a tag other than
    <code>&lt;a&gt;</code> or <code>&lt;button&gt;</code> for interactive
    spabutton class="btn span-btn">This is a span pretending to be a button</spabutton>

    <h2>Keyboard Triggering</h2>
    Links are triggered with the Enter key, buttons are triggered with the
    Space or Enter key. Links with a button role should account for that.
    <a href="#anchor" class="btn link-btn" role="button"
    >This is a link with a button role</a

    <h2>Pointer Cursor</h2>
    The pointer cursor shouldn't be on anything but links, because of their
    weak affordance.
    >[<a href="https://www.w3.org/TR/CSS21/ui.html#propdef-cursor">1</a
    <button class="btn pointer-btn">This is a button, not a link</button>

    <h2>Last Resort</h2>
    There are times when you absolutely can't use <code>&lt;a&gt;</code> or
    <code>&lt;button&gt;</code>, in these cases you must provide the semantic
    meaning and functionality.
    <div class="btn div-btn"
    role="button" tabindex="0">
    This is a div pretending to be a button

    <script src="buttons-and-links.js"></script>


    Comparing /examples/semantics/buttons-and-links/before/buttons-and-links.css to /examples/semantics/buttons-and-links/after/buttons-and-links.css

    .btn {
    border: 1px solid #333;
    border-radius: 5px;
    color: #333;
    cursor: pointer;
    font-size: 16px;
    font-weight: normal;
    padding: 8px;

    .div-btn {
    display: inline-block;

    .link-btn {
    color: #333;
    text-decoration: none;

    .link-btn:visited {
    color: #333;

    .span-btn {

    cursor: default;

    display: inline-block;


    Comparing /examples/semantics/buttons-and-links/before/buttons-and-links.js to /examples/semantics/buttons-and-links/after/buttons-and-links.js

    (function () {
    'use strict';

    const divBtn = document.querySelector('.div-btn');
    const linkBtn = document.querySelector('.link-btn');
    const pointerBtn = document.querySelector('.pointer-btn');
    const spanBtn = document.querySelector('.span-btn');

    // Set up example event listeners and click events
    divBtn.onclick = clickEvent;
    linkBtn.onclick = clickEvent;
    linkBtn.addEventListener('keydown', activateEvent);
    pointerBtn.onclick = clickEvent;
    spanBtn.onclick = clickEvent;
    spanBtn.addEventListener('keydown', activateEvent);

    function clickEvent() {
    alert('Hey, you clicked a button-like element!');


    function activateEvent(e) {
    if (e.key === 'Enter' || e.code === 'Space') {