/// Layout
LinkOverlay
A stretched-link helper that makes a whole Card or Tile clickable through one keyboard-correct anchor.
import { LinkOverlay, LinkBox } from "@protocore/pds";A clickable card
Wrap the surface in LinkBox (which sets position: relative) and drop a LinkOverlay anywhere inside. Its ::after covers the whole box, so the entire card is the click target — but the DOM still holds exactly one real anchor, so keyboard and screen-reader behaviour stays correct.
Trasor
Static site tenant · 4 environments · last deploy 3m ago. The whole card links through one anchor.
With a secondary action
A second interactive element inside the box (a button, an outbound link) stays clickable by raising its own stacking context — position: relative; z-index: 1. It sits above the overlay while the rest of the card still routes to the primary link.
Roxana
The card links to the tenant, while the live-site link below stays independently clickable.
Why not wrap the card in an anchor
This is the affordance-honesty law (§7.2) made reusable. Wrapping a whole card in an <a> is invalid when the card contains other links or buttons, and an onClick on the surface is invisible to the keyboard and to assistive tech. The stretched-link pattern gives you one real, focusable, announceable anchor whose hit area is the entire surface.
LinkOverlay supports asChild, so you can hand it your framework's Link (Next, Remix) and keep client-side navigation. Give the surface a visible hover/focus affordance only when it is genuinely interactive — the whole point is that it now is.
Usage
Do
- Wrap the surface in `LinkBox` (or set `position: relative` yourself).
- Keep exactly one primary `LinkOverlay` per box.
- Raise secondary actions with `position: relative; z-index: 1`.
- Use `asChild` to pass a framework `Link` for client navigation.
Don't
- Wrap the whole card in an `<a>` — invalid with nested interactives.
- Put two overlays in one box; the hit areas will fight.
- Add an `onClick` to the surface instead; that skips the keyboard.
Accessibility
| Keys | Action |
|---|---|
| Tab | Moves focus to the single overlay anchor |
| Enter | Activates the link |
- Exactly one anchor is in the accessibility tree, so screen readers announce one link for the whole surface.
- The focus ring is moved onto the stretched `::after`, so keyboard focus outlines the entire surface rather than a zero-width inline anchor.
LinkOverlay props
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | — | Merge props onto the single child instead of rendering an `<a>` (framework links). |
className | string | — | |
style | CSSProperties | — |
LinkBox props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | |
style | CSSProperties | — |