Photo by Mediamodifier on Unsplash
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
- Set
position: relative
on the container element - Set
position: absolute
on the link’s:after
pseudo-content - Set value of
0
fortop
,right
,bottom
, andleft
properties on link’s:after
pseudo-content - Combine it with
:focus-within
and:hover
to style different states - Enhance it even further and make the text selectable with
z-index
- 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.