Select theme appearance

Accessible Card Links

(Yet another) definitive guide on how to build a card that works like a link. Think product links or blog posts. Because there are too many doing it wrong.

  • Tags:  Component Library, Web Development
  • Last updated:  

My girlfriend has been doing a lot of accessibility research lately and has looked at a lot of websites as guidance for the European accessibility act. We’ve been talking about it a lot and most websites do card links wrong.

What is wrong

  • Multiple links with the same target. Some screenreader users will create link lists and that noise at this point.
  • Wrapping the whole card in a link. That’s better, but creates a LONG link text. It’s also confusing when you want another link INSIDE the card.
  • Not using a link at all. Well, what should I say. The button vs link debate is another topic.

Doing it right

So what we want:

  • Good semantic HTML structure
  • One link with clear link text
  • The whole card should still be clickable and have visible hover and focus styles

The markup

The markup is from our very own nordcode “component library”. It’s more of a documentation and a style package.

Here’s the full docs on clickable cards

<article class="nc-clickable-card nc-stack";
    padding: var(--spacing-base);">
    <img src="/preview.jpg" alt="">
    <h2>
        <a href="#" data-link="main">Here we go again</a>
    </h2>
    <p>After seeing to many inaccessible cards, it was time to warm the topic up again.</p>
    <div class="nc-cluster nc-hint">
        <time>Today</time><span>-</span><span>Joshua</span>
    </div>
</article>

and this is the actual CSS we use:

:where(.nc-clickable-card) {
    cursor: pointer;
    position: relative;

    &:focus-within,
    &:hover {
        outline: var(--border-width-medium) solid var(--color-brand-primary-base);
    }

    & a[data-link="main"] {
        text-decoration: none;

        &:focus-within:focus-visible,
        &:hover {
            outline: none;
        }

        &:before {
            content: "";
            position: absolute;
            inset: 0;
        }
    }

    & a[data-link="extra"] {
        position: relative;
    }
}

Keep the data-link attribute in mind, we’ll return to it later. For your own project, you can also ignore that and change the main link to a simple a rule.

Why it works

If you looked at the code on the page, you’ll notice that the whole card is focussable, clickable and has a hover effect. Well, it appears to have it.

The actual link is inside the article’s title. and only that is focused. The rest is CSS.

By using position: relative and an pseudo-element that spans the whole card, the whole card becomes clickable. The rest is leveraging :focus-within. That’s it.

Extras

Let’s say you want an additional link to the article’s author. Easy. Add it to the cards and use data-link="extra". By applying position: relative to the extra-link, it remains clickable.

If the link comes before the main link, you’ll have to use z-index, to place it above the clickable link.

An optional Read more faux button or link can be added. You can apply your own styles there. It’s probably a good idea to add aria-hidden="true" to it, to hide it from screen readers.

If you really want, you can also add some screen reader only text before the link target, like “Read the article about:” by using a .sr-only class.


That’s it. Now go and create better cards. Thanks for reading!

Better articles on it