Clickable Card Patterns and Anti-Patterns

Published: (December 16, 2025 at 08:04 AM EST)
2 min read
Source: Dev.to

Source: Dev.to

Problem with nesting interactive elements

  • HTML Specification – A hyperlink (<a> with an href) is interactive content. According to the HTML Living Standard, an interactive element must not contain other interactive or focusable elements as descendants, which prohibits a hyperlink from containing elements like <button>, <input>, or another <a>.
  • Assistive‑technology issues – Screen readers and keyboard navigation encounter two different links with overlapping hit areas. Tabbing behavior becomes unpredictable, and the link name (as read out by screen readers) becomes the card’s entire contents.

Author: Jamil.

The goal is to keep the primary link (e.g., the card title) separate from secondary interactive elements while using CSS to expand the primary link’s hit area to cover the whole card. Internal links or buttons are positioned above the stretched link so they retain their own interaction priority.

HTML structure

<div class="card">
  <a href="/article/123" class="card__main-link">
    <h3>Article Title</h3>
  </a>

  <img src="thumbnail.jpg" alt="Article Thumbnail">

  <p>Author: <a href="/authors/jamil">Jamil</a>.</p>
</div>

Key CSS properties

ElementKey CSS PropertiesFunction
.cardposition: relative;Establishes the stacking context for absolute children.
.card__main-link::aftercontent: ''; position: absolute; inset: 0; z-index: 1;Stretches an invisible link across the whole card to act as the primary click target.
Inner interactive elements (a, button)position: relative; z-index: 2;Lifts these elements above the stretched link’s hit area, preserving their functionality and focus order.

CSS implementation

/* 1. Parent element context */
.card {
  position: relative;
  /* Other styles (border, padding, etc.) */
}

/* 2. Stretched click area */
.card__main-link::after {
  content: '';
  position: absolute;
  inset: 0;               /* top: 0; right: 0; bottom: 0; left: 0; */
  z-index: 1;            /* Less than the inner interactive elements */
  pointer-events: auto;  /* Ensure the area is clickable */
}

/* 3. Priority for internal interactive elements */
.card p a,
.card button {
  position: relative;
  z-index: 2;            /* Above the stretched click area */
}

Using the Stretched Link Pattern resolves the conflict between design intent (making the card fully clickable) and technical compliance (avoiding nested interactive elements). By preserving correct HTML semantics and managing the stacking context, developers and designers can create robust, fully accessible components that provide a predictable user experience.

Photo by gabby‑k

Back to Blog

Related posts

Read more »

3D Walkman - Pure CSS

!Forem Logohttps://media2.dev.to/dynamic/image/width=65,height=,fit=scale-down,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%...