Skip to main content
Urbicon UI
← Back to Recipes

Clickable Card

Card as one fully clickable element — dashboard tile, list card, navigation tile. Card automatically renders as <a> or <button> depending on the prop; nested <a><Card></Card></a> is unnecessary (and usually wrong).

Card

Live Preview

List card with action (onclick)

Features

  • href automatically sets the rendered element to <a> with correct tab order
  • onclick sets it to <button type="button"> for actions without navigation
  • Hover/focus styles kick in automatically once href/onclick/clickable is set — no "decorative hover" mode on passive elements
  • mint="lift" or mint="glow" for a gentle micro-interaction
  • Anti-pattern comparison: why <a><Card></Card></a> is the worse solution

Code

Stat tile with href (renders as <a>)

Loading...
Loading syntax highlighting...

List card with onclick (renders as <button>)

Loading...
Loading syntax highlighting...

Delegate click without onclick (clickable prop)

Loading...
Loading syntax highlighting...

Anti-pattern: wrapping Card in <a>

Don't

<a href="/revenue">
  <Card variant="outlined" padding="md">
    Content
  </Card>
</a>
  • Card keeps elementType="div" — no hover/focus styles
  • Inner inputs/links produce nested interactive elements (a11y violation)
  • Two tab stops (outer a + card content) instead of one
  • Screen readers announce "link, region, …" twice

Do

<Card
  variant="outlined"
  padding="md"
  href="/revenue"
>
  Content
</Card>
  • Card renders directly as <a>
  • Hover/focus styles apply automatically
  • One tab stop, one element for screen readers
  • No conflicts with inner buttons (stop bubbling where needed)

Best Practices

href for navigation, onclick for actions

Routes, detail pages → href. Opening a modal, changing a selection, server actions → onclick. That way Cmd-click "open in new tab" works as expected.

Inner buttons: stopPropagation

If the card contains a secondary button (e.g. "Favorite"), end the button's onclick with event.stopPropagation() — otherwise the card fires too.

mint="lift" for a gentle hover animation

mint="lift" lifts the card slightly on hover; mint="glow" adds a subtle glow. prefers-reduced-motion is respected.

clickable for delegated click handlers

When click behavior is handled by a wrapper component and the card should render as a real button without carrying an onclick itself — set clickable without href/onclick. The card then renders as <button type="button"> with interactive styles. Don't combine it with an outer <a> or inner buttons — <a><Card clickable> produces nested interactive elements.

No "decorative hover"

Card deliberately has no mode with hover styles but no click source. A pointer cursor plus a lift animation on a passive element violates WCAG 3.2 Predictable. If the card sits inside an outer <a>, move the href onto the card (see the anti-pattern section).