Card
Flexible container for grouping related content with headers, footers, and interactive states.
Playground
<Card>
{#snippet header()}
<div class="font-semibold">Card Title</div>
<div class="text-text-tertiary text-xs">Optional subtitle</div>
{/snippet}
<div class="text-text-secondary text-sm">
Cards group related content. Change variant and padding to see different looks.
</div>
{#snippet footer()}
<div class="flex justify-end gap-2">
<Button variant="ghost" size="sm">Cancel</Button>
<Button variant="filled" intent="primary" size="sm">Confirm</Button>
</div>
{/snippet}
</Card>01 Examples
Choosing a variant
quiet is the default — a barely-tinted in-page zone, no border, no shadow. outlined adds a quiet outline when you need architectural delineation. elevated lifts the card with a shadow only. floating is for popover-family surfaces above arbitrary backgrounds.Quiet – subtle tint, default
Outlined – border only
Elevated – shadow only
Floating – popover surface
<Card variant="quiet">
<p class="text-text-secondary text-sm">Quiet – subtle tint, default</p>
</Card>
<Card variant="outlined">
<p class="text-text-secondary text-sm">Outlined – border only</p>
</Card>
<Card variant="elevated">
<p class="text-text-secondary text-sm">Elevated – shadow only</p>
</Card>
<Card variant="floating">
<p class="text-text-secondary text-sm">Floating – popover surface</p>
</Card>Stat tile
Monthly Revenue
$48,210
<Card padding="md">
<p class="text-text-tertiary text-xs font-medium tracking-wider uppercase">
Monthly Revenue
</p>
<p class="text-text-primary mt-2 text-3xl font-bold">$48,210</p>
<div class="mt-2 flex items-center gap-2">
<Badge size="xs" intent="success">+12.4%</Badge>
<span class="text-text-tertiary text-xs">vs. last month</span>
</div>
</Card>Profile card with header & footer
header and footer snippets render in semantically appropriate positions. Set dividers to draw hairline separators between header, body and footer for a more structured look.The latest build passed all 142 tests. Deployment is scheduled for Monday.
<Card variant="outlined" dividers>
{#snippet header()}
<div class="flex items-center gap-2">
<span class="font-semibold">Project Update</span>
<Badge size="xs" intent="success">New</Badge>
</div>
{/snippet}
<p class="text-text-secondary text-sm">
The latest build passed all 142 tests. Deployment is scheduled for Monday.
</p>
{#snippet footer()}
<div class="flex justify-end gap-2">
<Button variant="ghost" size="sm">Dismiss</Button>
<Button variant="filled" intent="primary" size="sm">View Details</Button>
</div>
{/snippet}
</Card>Clickable navigation card
href to render as <a> or onclick to render as <button> — hover styles activate automatically. Pair with mint="scale" for a subtle press affordance.<Card href="#documentation" mint="scale">
<div class="flex items-start gap-3">
<div
class="bg-primary/10 text-primary rounded-modify flex h-10 w-10 shrink-0 items-center justify-center font-semibold"
>
→
</div>
<div>
<p class="text-text-primary font-semibold">Read the documentation</p>
<p class="text-text-secondary mt-1 text-sm">
Browse component APIs, design tokens, and integration guides.
</p>
</div>
</div>
</Card>02 Customization
Gradient Feature Card
Advanced Analytics
Real-time dashboards, custom reports, and AI-powered insights for your team.
<Card
slotClasses={{
base: 'bg-linear-to-br from-violet-600 to-indigo-700 text-white border-none shadow-xl shadow-violet-500/25'
}}
padding="lg"
>
<div class="space-y-3">
<Badge
unstyled
class="rounded-full bg-white/20 px-3 py-1 text-xs font-medium text-white backdrop-blur-sm"
>
Pro Feature
</Badge>
<h3 class="text-xl font-bold">Advanced Analytics</h3>
<p class="text-sm text-white/80">
Real-time dashboards, custom reports, and AI-powered insights for your team.
</p>
<Button
unstyled
class="mt-2 rounded-lg bg-white px-4 py-2 text-sm font-semibold text-violet-700 transition-all hover:bg-white/90"
>
Get Started
</Button>
</div>
</Card>Glass Pricing Card
Premium
$29/mo
- Unlimited projects
- Priority support
- Custom integrations
<Card
unstyled
class="w-72 rounded-2xl border border-white/20 bg-white/10 p-6 text-white shadow-2xl backdrop-blur-xl"
>
<p class="text-sm font-medium tracking-wider text-white/70 uppercase">Premium</p>
<p class="mt-2 text-4xl font-bold">
$29<span class="text-lg font-normal text-white/60">/mo</span>
</p>
<ul class="mt-4 space-y-2 text-sm text-white/80">
{#each ['Unlimited projects', 'Priority support', 'Custom integrations'] as perk (perk)}
<li class="flex items-center gap-2"><CheckIcon size={16} /> {perk}</li>
{/each}
</ul>
<Button
unstyled
class="mt-6 w-full rounded-xl bg-white py-2.5 text-center text-sm font-semibold text-fuchsia-600 transition-all hover:bg-white/90"
>
Subscribe
</Button>
</Card>Dark Minimal
Lightning Fast
Zero-config bundling with sub-second hot reload and tree-shaking built in.
<Card
unstyled
class="rounded-2xl border border-neutral-800 bg-neutral-900 p-6 shadow-[var(--blocks-shadow-lg)]"
>
<div class="flex items-start gap-4">
<div
class="bg-primary/20 text-primary flex h-10 w-10 shrink-0 items-center justify-center rounded-xl"
>
<ZapIcon size={20} />
</div>
<div>
<h4 class="font-semibold text-neutral-100">Lightning Fast</h4>
<p class="mt-1 text-sm text-neutral-400">
Zero-config bundling with sub-second hot reload and tree-shaking built in.
</p>
</div>
</div>
</Card>A hero-card look reused across marketing surfaces belongs in a BlocksProvider preset (presets.Card), applied via preset — see Customization.
03 Accessibility
Built-in ARIA
Cards render as <div> by default. When clickable or onclick is set, the card renders as <button>. When href is provided, it becomes an <a>. Disabled cards set aria-disabled.
Keyboard
Interactive cards are focusable via Tab and activate with Enter / Space. Non-interactive cards are skipped in the tab order.
Structure
Header and footer snippets are rendered in semantically appropriate positions. Use headings inside headers to create a scannable document outline for screen readers.
04 API Reference
Prop | Type | Default | Description | |
|---|---|---|---|---|
children | Snippet | — | Content to render inside the Card component | |
class | string | — | Extra classes merged onto the root element. | |
clickable | boolean | — | Force <button> rendering and interactive hover styles without
providing an onclick handler — useful when delegating clicks
through a wrapper component or library. onclick and href
already enable interactive styles automatically; reach for
clickable only when neither is appropriate.
Don't combine with an outer <a href> or inner interactive
content — <a><Card clickable>…</Card></a> produces nested
interactive elements (invalid HTML, a11y violation). Prefer
<Card href={…}> so the card itself becomes the anchor. | |
disabled variant | true | false | Controls the disabled behavior and appearance of the Card component. Available options: true. | |
dividers variant | true | false | Controls the dividers behavior and appearance of the Card component. Available options: true. | |
footer | Snippet | — | Content rendered below the body. With dividers, a hairline separates body from footer. | |
header | Snippet | — | Content rendered above the body. With dividers, a hairline separates header from body. | |
href | string | — | URL target. When provided, the card renders as <a>. | |
mint | MintProp | 'none' | Micro-interaction preset applied to the card. Only applies while the
card is interactive (clickable, onclick, or href) and not disabled. | |
onclick | (event: MouseEvent) => void | — | Click handler. When provided, the card renders as <button> and gains interactive styles. | |
onHover | (hovered: boolean) => void | — | Called when hover state changes. Receives true on mouse-enter, false on mouse-leave. | |
padding variant | lgmdnonesm +1 more | md | Controls the padding behavior and appearance of the Card component. Available options: lg, md, none, and 2 more. | |
preset | string | — | Apply a named preset registered via <BlocksProvider presets={{ Card: {...} }}>.
Prefer this over class overrides when the requested look falls outside the
semantic intent palette — presets keep hover/active/dark-mode logic coherent
and make the custom look reusable across the project. | |
slotClasses | Partial<Record<CardSlots, string>> | — | Per-slot class overrides. Slots: base | header | content | footer | |
tier variant | bridgecontain | contain | Selects the semantic radius tier of the Card — the shape family it belongs to (--radius-commit/-modify/-contain/-bridge). Shape is retuned per family in your theme, so this picks the family rather than a pixel value. Available options: bridge, contain. | |
unstyled | boolean | — | Remove all default tv classes. | |
variant variant | elevatedfloatingoutlinedquiet | quiet | Controls the visual style and presentation of the Card. Determines the component's visual treatment. Available options: elevated, floating, outlined, quiet. | |
...CardVariants variant | VariantProps | — | Styling variants from CardVariants | |
...HTMLAttributes<HTMLElement> inherited | HTMLAttributes | — | HTML attributes (excluding: 'children') |
05 Types
Local type definitions used by this component.
Name | Kind | Category | Used by | Description | |
|---|---|---|---|---|---|
CardProps | interface | props | 0 | — | |
CardVariants | type | variant | 0 | — | |
CardSlots | type | variant | 0 | Slot names derived from the tv() config — single source of truth for slotClasses. | |
MintProp | type | helper | 1 | — | |
MintName | type | helper | 0 | A mint name: a built-in (autocompleted), 'none' to disable, or any
consumer-registered name. (string & {}) keeps the registry open — a
custom name still type-checks, it just isn't suggested. A typo therefore
also still compiles (it resolves like an unregistered custom name and
warns at runtime); the union buys completion and docs, not validation. | |
MintConfig | interface | helper | 0 | — | |
BuiltinMintName | type | helper | 0 | Built-in mint names as a literal union, so the mint prop autocompletes
across every component — the single list the hand-curated playground knobs
and docs used to drift away from. |
06 Installation
Import
import { Card } from '@urbicon-ui/blocks';