Accessible card component

With pure (S)CSS (no JavaScript, the pseudo-content trick)

When creating the card component, sometimes it’s advisable (or required by design) to make the whole card clickable. But how to do so without compromising the usability? Below I share a useful pseudo-content trick to make the whole card clickable and maintain its accessibility.

Problem statement

  • the whole card needs to be clickable
  • within the card there is also a “read more” link
  • inside a card, there are other separate links to different URL-s
  • you don’t want to harm the usability, e.g. allow the user to open all links in a new tab with a mouse right-click (context menu on touch devices)
  • support custom styles for hover and focus states
  • one last requirement: user should be able to select and copy the text within a card to the clipboard

How would you approach this task? Just a regular card component wrapped in an a element? Or maybe onclick in JavaScript directly on a div or article element (don’t do that!)?

How to handle such a case and maintain the accessibility in a simple and elegant way?

Possible solution

  1. Set position: relative on the container element
  2. Set position: absolute on the link’s :after pseudo-content
  3. Set value of 0 for top, right, bottom, and left properties on link’s :after pseudo-content
  4. Combine it with :focus-within and :hover to style different states
  5. Enhance it even further and make the text selectable with z-index
  6. If you want to add other links inside a card, use styles from card__separate to make it selectable (and/or clickable).

HTML

<div class="card">
  <p>
    <a href="#optional" class="card__separate">Optional</span>
  </p>
  <p>
    <span class="card__separate">Lorem ipsum</span>
  </p>
  <a href="#card-link" class="card__link">Link</a>
</div>

SCSS

.card {
  position: relative;
  border: 3px solid green;

  // Style hover and focus states.
  &:hover,
  &:focus-within {
    border-color: red;
  }

  // Make the content selectable.
  &__separate {
    position: relative;
    z-index: 2;
  }

  // Make the whole card clickable.
  &__link::after {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    content: "";
  }
}

Demo

Check clickable area (start with "Button 1") and try tab keyboard navigation in the following example:

Credits & further reading

I first saw the pseudo-content trick technique on Inclusive Components website. Check it out for other solutions to card issues and more inclusive components examples.