Build the card around what it does: use an HTML link when activating it navigates to a resource, and a button when it reveals information or performs an action on the current page. HTML supplies the control’s meaning and keyboard behavior; CSS makes its appearance and interactive states clear.
Choose the card’s behavior before choosing its markup
A card’s visual shape does not determine its semantics. Decide what activation should do, then use the native element that matches that purpose. A link navigates; a button performs an action. The WAI-ARIA Authoring Practices Guide (APG) describes those distinct purposes in its guidance on links and buttons.
As an Amazon Associate I earn from qualifying purchases.
| Decision | Navigation card | Disclosure or action card |
|---|---|---|
| Purpose | Navigate to a resource | Change or reveal something in the current interface |
| Native control | An anchor with an href |
A button |
| Keyboard activation | Enter activates the link | Enter or Space activates the button |
| What to communicate | A meaningful destination and link name | A clear action name and, for disclosure, whether content is expanded |
These are common patterns, not the only possible card designs. The right choice follows the action, not the desire to make a large area clickable.
Build a card that navigates
Use a real anchor with a meaningful href. A useful structure is a self-contained article whose heading contains the link. This keeps the destination easy to find and avoids wrapping every descendant in one oversized link.
#1 Best Overall
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
<article class="card">
<h2><a class="card__link" href="/guides/keyboard-accessibility/">
Keyboard accessibility
</a></h2>
<p>Learn how native controls support keyboard use.</p>
</article>
The W3C Design System’s card guidance warns that putting all card content inside a single anchor can result in screen-reader users hearing the entire contents as the link. A heading link is a straightforward alternative. If the design needs a larger hit area, the Design System also describes a block-link enhancement; use it without absorbing separate links or controls into the same link.
Style the link without removing its cues
CSS can make the card and link look like a unified surface, but it does not turn a non-link element into a semantic link or supply its keyboard behavior. Preserve an obvious focus indicator as well as a hover treatment.
Rank #2
.card {
border: 1px solid #687386;
border-radius: 0.75rem;
padding: 1.25rem;
}
.card__link {
color: inherit;
text-decoration-thickness: 0.12em;
text-underline-offset: 0.18em;
}
.card__link:hover {
text-decoration-thickness: 0.2em;
}
.card__link:focus-visible {
outline: 3px solid currentColor;
outline-offset: 4px;
}
Adjust colors and spacing to the surrounding interface, but ensure the link remains identifiable and the keyboard focus remains visible.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Build a card that reveals details
For a disclosure, give users a native button and expose its current state with aria-expanded. The state must match whether the controlled content is visible. Give the button a useful name: a short label such as “Details” can gain context from the card heading.
Rank #3
<article class="card" aria-labelledby="plan-title">
<h2 id="plan-title">Standard plan</h2>
<button class="card__toggle" type="button"
aria-expanded="false" aria-controls="plan-details">
Details
</button>
<div id="plan-details" hidden>
<p>Includes the features described for this plan.</p>
</div>
</article>
When activated, update both the visibility and aria-expanded. For example, this small script handles one disclosure button:
const button = document.querySelector('.card__toggle');
const details = document.getElementById(button.getAttribute('aria-controls'));
button.addEventListener('click', () => {
const willExpand = button.getAttribute('aria-expanded') !== 'true';
button.setAttribute('aria-expanded', String(willExpand));
details.hidden = !willExpand;
});
For multiple cards, scope each button to its own controlled content rather than reusing one global element. The APG’s disclosure-card example demonstrates contextual button naming, expanded state, and keyboard interaction. Its example is illustrative, not a ready-made production component.
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Keep independent controls independent
If a disclosure card also contains a link, form field, button, or clickable label, activating that control should not accidentally toggle the card. Prefer listening on the disclosure button itself, as in the example above, instead of making the entire card respond to clicks. If an existing design uses card-level click handling, explicitly prevent nested controls from triggering it and test each control separately.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallMake interaction visible and test the result
Hover alone is not enough: keyboard users need a visible focus state, and people should be able to distinguish an expanded disclosure from a collapsed one. Use CSS for those visual signals, while leaving activation and state semantics to the native controls and the disclosure logic.
Best Value
.card__toggle {
border: 1px solid currentColor;
border-radius: 0.35rem;
padding: 0.5rem 0.75rem;
}
.card__toggle:hover {
text-decoration: underline;
}
.card__toggle:focus-visible {
outline: 3px solid currentColor;
outline-offset: 3px;
}
.card__toggle[aria-expanded="true"]::after {
content: " −";
}
.card__toggle[aria-expanded="false"]::after {
content: " +";
}
@media (prefers-reduced-motion: reduce) {
.card, .card * {
scroll-behavior: auto;
transition-duration: 0.01ms;
animation-duration: 0.01ms;
}
}
@media (forced-colors: active) {
.card__toggle:focus-visible,
.card__link:focus-visible {
outline-color: Highlight;
}
}
Check the component with a keyboard: Tab should reach each control, Enter should activate a link, and Enter or Space should activate a button. Confirm that the disclosure state and visible content stay in sync, that focus is apparent, and that nested controls do not trigger unrelated actions. The APG notes that its guidance is informative rather than a normative standard; following an example alone does not establish that a component conforms to WCAG. See the APG introduction for the guide’s scope and limitations.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




