A11Y Solutions
Provides auto-suggestions when entering text

    Link Anti-patterns

    Links are most useful when they are discoverable and have a predictable outcome.

    The Problem

    When links are disguised in another tag or are improperly formatted, they become harder to find and may have unexpected outcomes.

    The Solution

    Anything that behaves like a link should use an <a> tag with an href, anything else should use a <button>

    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/navigation/link-anti-patterns/before/index.html to /examples/navigation/link-anti-patterns/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 - Navigation - Link Anti-patterns</title>
    <link rel="stylesheet" href="../../../presentation.css" />
    <link rel="stylesheet" href="link-anti-patterns.css" />
    <body id="top">
    <h1>Links Anti-pattern examples</h1>
    <h2>Using Improper Tags</h2>
    We lose discoverability when using a tag other than
    <code>&lt;a&gt;</code> for links, they're not in the tabindex nor in the
    list of links in VoiceOver Rotor.
    span class="link span-linka href="#bottom" onclick="scrollToBottom(event)"
    >This is
    a span pretending to be a linklink to the bottom of the page</span

    <h2>Link without an href</h2>
    Links that don't have an href and rely on JavaScript are not fully
    discoverable either, they're often removed from the tabindex.
    class="linkhref="#bottom" onclick="scrollToBottom(event)"
    >This is a link with
    out an href fallback</a

    <h2>Interactive controls that don't behave like a link</h2>
    The opposite issue as above, when a link has an <code>href="#"</code> or
    similar, chances are it'd be better suited as a button.
    a class="link" href="#"button onclick="doSomething()">
    >This is a linkbutton that should be a does something

    <h2>Linked image without alt text</h2>
    Without alternative text, a linked image is not fully discoverable either.
    <a href="#bottom" onclick="scrollToBottom(event)">
    <img src="/img/logo.svg" width="180" alt="Accessibility Solutions" />

    <div class="super-long-space"></div>
    <a href="#top" id="bottom" onclick="scrollToTop(event)"
    >Going up? Back to top</a

    <script src="link-anti-patterns.js"></script>


    Comparing /examples/navigation/link-anti-patterns/before/link-anti-patterns.css to /examples/navigation/link-anti-patterns/after/link-anti-patterns.css

    .link {
    color: #dc3542;
    font-weight: bold;
    transition: all 0.3s ease;

    .link:focus {
    color: #d21a28;
    cursor: pointer;
    text-decoration: underline;


    Comparing /examples/navigation/link-anti-patterns/before/link-anti-patterns.js to /examples/navigation/link-anti-patterns/after/link-anti-patterns.js

    function doSomething() {
    alert('did something');

    function scrollToBottom(e) {
    const anchor = document.querySelector(e.currentTarget.getAttribute('href'));
    window.scrollTo({ top: document.body.scrollHeightanchor.offsetTop, behavior: 'smooth' });

    function scrollToTop(e) {
    window.scrollTo({ top: 0, behavior: 'smooth' });