Back to writing

Accessible Nested Links

January 10, 2024

How to make a whole card clickable without nesting links or relying on JavaScript.

You have a clickable card. Inside that card, you also have other interactive elements.

You want the whole card to open the main destination, while still letting people click the secondary links inside it.

The first instinct is often to nest links. That is invalid HTML and an accessibility problem.

The second instinct is usually JavaScript. That works, but it is often more moving parts than you need.

There is a cleaner CSS-only pattern.

Start with valid HTML

Here is the basic structure:

<div class="card">
  <a href="/posts/accessible-nested-links" class="cta">
    Accessible nested links
  </a>
  <p>How to accessibly nest links with only CSS.</p>
  <a href="/about">By Tom Slutsky</a>
</div>

This markup is valid and accessible. The problem is that only the text of the main link is clickable.

Expand the main link with CSS

.card {
  position: relative;
}
 
.card > a {
  position: relative;
  z-index: 1;
}
 
.cta::before {
  content: "";
  position: absolute;
  inset: 0;
}

The trick is to use a pseudo-element on the main link and stretch it across the card.

Now clicking anywhere on the card is effectively clicking that main link.

The z-index on the links inside the card lifts them above the overlay so they still work as independent targets.

Why this works well

This keeps the markup honest, avoids a JavaScript click trap, and preserves keyboard behavior as long as the main link appears first in the card.

That is a good deal for a tiny amount of CSS.