The card mistake you've been making that has been hurting your app's accessibility.
Tags: webdev, javascript, frontend, html
Published: 2024-02-16 08:19:26

**If** you are a frontend developer, or if you have been practicing frontend development either professionally or in your spare time, chances are you have probably created some form of a _card_ in a web application. If you don't know what I'm talking about, a card in this context is basically a UI design pattern that groups related information in a flexible-size container visually resembling a playing card. Think of Netflix's homepage, those small rectangles that represent a movie or a TV series, each one of those is basically a card.

![A card from Netflix's website containing information about the movie "The Guilt Trip"](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0qjmg96s0b0g6idgd3u4.png)

One feature of those cards that is often implemented by developers and designers is that the **whole** card is clickable and most probably is a link to some other place; a movie page, an article, a post, etc.

That makes a lot of sense; a card is most probably a summary of some content that you think the user might be interested in. It likely contains an image, a title, a brief description, and some other relevant metadata pertaining to the nature of the content. So, you are creating it to lure the user into clicking it to be taken to the full content. Pretty straightforward, right?

## The Problem

I have seen a lot of projects over the years, and pretty much **ALL** the time, I've seen people do the following when developing the card: the whole card should be clickable, so let's wrap the entire content of the card in an `<a>` tag. Or a `<Link>` tag if you're using React/Next (Which is just an extension of the `<a>` tag). And that works just fine. So what's the problem with that?

The problem comes when thinking about **accessibility**. Think about this, a person using a screen-reader would want the information to be as straightforward and as clear as possible. Have you ever tried using a screen-reader? It's pretty daunting! It reads out the entire content of the webpage. So, if you have a card with an image, a lot of text, and metadata, you, as the user, would have to wait out the assistive technology to read out **ALL** that content until it tells you that it's actually a link. That has probably already exhausted you just thinking about it.

## An Example

Let's go through an example from a web application that I have been absolutely obsessed with. You've probably heard about [movie-web.app](movie-web.app). It's an open-source streaming web application that uses a clever way to fetch any movie or TV show you would want to stream. I've been spending a lot of time navigating their codebase, so let's take a look at how they have implemented cards. First of all, their cards look like this:

![4 cards containing information about Harry Potter's movies from movie-web.app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkvgt7wgalshkr7zcgol.png)

These are 4 cards, and here's how they implement each one:

```js
import { Link } from "react-router-dom";
  return (
    <Link
      to={link}
      tabIndex={-1}
      className={classNames(
        "tabbable",
        props.closable ? "hover:cursor-default" : "",
      )}
    >
      {content}
    </Link>
  );

```

As you can see, they wrap the entire card in a `react-router-dom` `<Link>` tag. Which, as we already mentioned, is just an extension of the native HTML `<a>` tag.

Now, it's important to note that in this particular case, that implementation is not much of a problem if any. Because the card contains just the title of the movie, and that's really the minimal information you would need to put inside a simple `<a>` tag for a movie. However, consider this example of a card from The Guardian's website:

![Two cards containing two articles from the Guardian](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w9wv00d1focieno2g5gt.png)

Now, if those cards were implemented the same way, you can visually see the amount of content the reader will have to read out until it shares the information that all of this is in fact a link. Now you can see the problem.

This is a common pattern that I see the majority of developers mistakenly follow. Because accessibility is generally not that high on everyone's priority list. But it's an issue that needs addressing and needs to be common practice to avoid.

## The Solution

Okay. I understand the problem now. But I still need to make a card and I need to make it a clickable link that's also accessible. How can I do that?

It's quite simple really. You just need to be clever with your CSS.

First of all, you probably guessed it, you need to wrap the card in a semantic HTML element such as `<article>`. Then, you can put an empty `<a>` tag inside with an `aria-label` that should take the user to the target page.

Then, to make the whole card clickable, you'll just need to do some simple CSS tricks to make the `<a>` tag take the whole width and height of the card and also increase its `z-index`. The HTML/JSX should look something like this:

```js
  return (
    <article
      className="card"
    >
      <h2>{title}</h2>
      <a href={link} aria-label={title}></a>
      <p>{desc}</p>
      <img src={img} alt={title} className="image" />
    </article>
  );
```

And the CSS should look something like this:

```css
.card {
    position: relative;
}
.card a::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 1;
}
```

You should also absolutely create a hover effect to visually indicate that the entire card is clickable, but that's a bit beyond the scope of this article.

## Conclusion

Web Development is fun. And, for me, one of the most fun and fulfilling aspects about it is the ability to make something that can be used by anyone, anywhere in the world. That's why while accessibility might be an inconvenience to some developers, it really isn't for me. Just think about this. You're making software that **more** users will enjoy!

If you have any questions or suggestions, or if I have made a mistake, please feel free to contact me! ❤️