---
title: "Make a whole card clickable with one stretched link · Ihab Khattab"
description: "Don't wrap a card in an <a> to make it clickable. Stretch the title link over it with ::after, and screen readers announce just the title."
url: "https://ihabkhattab.com/til/stretched-link-card/"
---

# Make a whole card clickable with one stretched link

Oct 29, 2026 · [Also on X](https://x.com/HO_BA/status/2115846581370962161)

Don’t wrap a card in an `<a>` to make it clickable. Stretch the title link over it with `::after`, and screen readers announce just the title.

This is based on Heydon Pickering’s [Cards chapter of Inclusive Components](https://inclusive-components.design/cards/):

```html
<ul class="cards" role="list">
  <li class="card">
    <h3>
      <a href="/trips/lisbon/">Lisbon</a>
    </h3>
    <p>4 nights, from $620</p>
    <img src="lisbon.jpg" alt="" />
  </li>
</ul>
```

```css
.cards {
  list-style: none;
  padding: 0;
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
}

/* Shown first, read after the heading */
.card img {
  order: -1;
}

.card h3 a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.card:has(h3 a:focus-visible) {
  outline: 2px solid;
  outline-offset: 3px;
}

.card h3 a:focus-visible {
  outline: none;
}
```

The heading comes before the image in the source. If the image came first and had alt text, people jumping between headings would skip it. Here it’s decorative, so its `alt` is empty.

The cards are in a list so screen readers announce how many there are, like “list, 3 items”. Safari stops treating a list as a list once `list-style: none` hides its bullets, so `role="list"` puts that back.

Positioned elements without a `z-index` paint in source order, so anything positioned after the title link covers the overlay. Use that for other links in the card, like an author name: `position: relative` lifts them above it, and one before the title link also needs a `z-index`. It can also catch you out. On the homepage, the screenshot’s image is positioned and comes after the heading, so the screenshot needs `pointer-events: none` to let clicks through.

The overlay also covers the card’s text, so it can’t be selected. If that matters, Heydon’s chapter has a JavaScript version that forwards clicks on the card to the link and keeps the text selectable.

The project cards on [the homepage](https://ihabkhattab.com/) used to be wrapped in an `<a>`. Chrome’s accessibility panel showed the link’s name as everything in the card, too long to fit:

![Chrome DevTools accessibility panel for the old wrapped card link. Its computed name starts “Screenshot of mdfor.dev mdfor.dev A fast” and runs off the edge.](https://ihabkhattab.com/_astro/stretched-link-card-before.BVmdkTSk_Z1OwisE.webp)

An empty `alt` alone wouldn’t fix it. Most of that name is the card’s description, and any text inside the `<a>` ends up in the name.

With the stretched link, the name is just the project name:

![Chrome DevTools accessibility panel for the stretched card link. Its computed name is “mdfor.dev”.](https://ihabkhattab.com/_astro/stretched-link-card-after.DsmMRdJk_uDMzQ.webp)

[← All TILs](https://ihabkhattab.com/til/)
