Makes an entire area clickable without common accessibility issues.
- Full keyboard navigation
- Supports modified clicks (e.g. shift+click)
- Allows text selection & image dragging within Card
- Can exclude portions of Card for nested interactivity
yarn add @timhettler/radix-cardImport the components and piece the parts together.
import * as Card from "@timhettler/radix-card";
export default () => (
<Card.Root>
<Card.Target></Card.Target>
<Card.TargetDescription></Card.TargetDescription>
<Card.Exclude></Card.Exclude>
</Card.Root>
);The clickable element which contains all the parts of the card.
| Prop | Type | Default |
|---|---|---|
asChild |
boolean |
false |
| Data Attribute | Value |
|---|---|
[data-target-focused] |
Present when target is focused |
The element that is triggered by clicks on the card Root.
| Prop | Type | Default |
|---|---|---|
asChild |
boolean |
false |
An optional element that provides additional semantic information about the card Target.
| Prop | Type | Default |
|---|---|---|
asChild |
boolean |
false |
An optional element that allows clicking within it without triggering the card Root.
| Data Attribute | Value |
|---|---|
[data-exclude] |
Always present on element |
See the project's Storybook for live examples.
Use the Root and Target elements to create an interactive container.
import React from "react";
import * as Card from "@timhettler/radix-card";
export default () => (
<Card.Root>
<h2>Graphic Design</h2>
<div>
Graphic design is a profession, academic discipline and applied art whose
activity consists in projecting visual communications intended to transmit
specific messages to social groups, with specific objectives.
</div>
<Card.Target href="https://en.wikipedia.org/wiki/Graphic_design">
Learn More
</Card.Target>
</Card.Root>
);Use the TargetDescription element to provide more semantic link titles. Especially useful if multiple Cards are presented together. The link in this example will be read by AT's as "Link: Graphic Design, Learn More"
import React from "react";
import * as Card from "@timhettler/radix-card";
export default () => (
<Card.Root>
<h2>
<Card.Target href="https://en.wikipedia.org/wiki/Graphic_design">
Graphic Design
</Card.Target>
</h2>
<div>
Graphic design is a profession, academic discipline and applied art whose
activity consists in projecting visual communications intended to transmit
specific messages to social groups, with specific objectives.
</div>
<Card.TargetDescription>Learn More</Card.TargetDescription>
</Card.Root>
);Use the Exclude element if you have multiple interactive elements within a Card.
import React from "react";
import * as Card from "@timhettler/radix-card";
export default () => (
<Card.Root>
<h2>
<Card.Target href="https://en.wikipedia.org/wiki/Graphic_design">
Graphic Design
</Card.Target>
</h2>
<div>
Graphic design is a profession, academic discipline and applied art whose
activity consists in projecting visual communications intended to transmit
specific messages to social groups, with specific objectives.
</div>
<Card.TargetDescription>Learn More</Card.TargetDescription>
<Card.Exclude>
<h3>Related topics:</h3>
<ul>
<li>
<a href="https://en.wikipedia.org/wiki/Aesthetics">Aesthetics</a>
</li>
<li>
<a href="https://en.wikipedia.org/wiki/Color_theory">Color theory</a>
</li>
</ul>
</Card.Exclude>
</Card.Root>
);// index.jsx
import React from "react";
import * as Card from "@timhettler/radix-card";
export default () => (
<Card.Root className="CardRoot">
<h2>
<Card.Target
href="https://en.wikipedia.org/wiki/Graphic_design"
className="CardTarget"
>
Graphic Design
</Card.Target>
</h2>
<div>
Graphic design is a profession, academic discipline and applied art whose
activity consists in projecting visual communications intended to transmit
specific messages to social groups, with specific objectives.
</div>
<Card.TargetDescription>Learn More</Card.TargetDescription>
</Card.Root>
);/* styles.css */
.CardRoot {
cursor: pointer;
transition: box-shadow 100ms;
}
/* Apply interactive styles to the container when user hovers over the container or gives focus to the target */
.CardRoot:hover,
.CardRoot[data-target-focused] {
box-shadow: 0 0 0 0.25rem #5a5a5a;
}
/* Remove default interactive styling from the target */
.CardTarget {
color: inherit;
text-decoration: none;
&:focus {
outline: none;
}
}Allows a container to be interactive without affecting the usability of Link or Button WAI-ARIA design patterns within.
Card forwards clicks from the container to the Target link in JavaScript instead of stretching the link's hit area over the whole container (the common ::after { position: absolute; inset: 0 } overlay trick). This is deliberate: keeping the link at its natural size is what lets you select text and drag images anywhere in the card, and keeps nested interactive content (Exclude, secondary links) simple.
The trade-off is the browser's native link preview — the destination URL most browsers show in the status bar while hovering a link. That preview is browser chrome tied to the actual element under the pointer, so it only appears over the real Target, not across the whole card. It can't be reproduced synthetically (the legacy window.status hook is a no-op in modern browsers). Interactive affordances like cursor: pointer and :hover styling are recoverable — apply them to Root (see Providing an Adequate Visible Focus Indicator) — but the URL preview itself is not.
The overlay approach makes the opposite trade: you get the native URL preview and native navigation for free, but the overlay sits on top of the content, which breaks text selection and forces nested interactive elements to be lifted above it. This component intentionally prioritizes selectable content.