Cards

Cards are flexible containers that group related content and actions. They provide a clean, elevated surface for displaying everything from simple text to complex interactive layouts.


Installation

Copy the card CSS from styles/docs.css or include the Standard stylesheet:

<link rel="stylesheet" href="standard.min.css">

Then use card classes in your HTML:

<div class="Card">
    <div class="Card-body">
        <h3 class="Card-title">Card Title</h3>
        <p class="Card-text">Card content goes here.</p>
    </div>
</div>

Usage

The base .Card class provides core styling with elevation and border radius. Add sections like .Card-header, .Card-body, and .Card-footer to structure content.

Simple Card

Cards group related content and actions together.

<div class="Card" style="max-width: 320px;">
<div class="Card-body">
<h3 class="Card-title">Simple Card</h3>
<p class="Card-text">Cards group related content and actions together.</p>
</div>
</div>

Examples

Basic Card

A minimal card with title and text content.

Project Update

The new dashboard feature is ready for review. All tests passing.

<div class="Card" style="max-width: 320px;">
<div class="Card-body">
<h3 class="Card-title">Project Update</h3>
<p class="Card-text">The new dashboard feature is ready for review. All tests passing.</p>
</div>
</div>

Use header and footer sections for titles, metadata, and actions.

Weekly Report

Feb 3, 2026

Revenue increased 12% this week. Customer satisfaction scores remain high at 4.8/5.

<div class="Card" style="max-width: 320px;">
<div class="Card-header">
<h3 class="Card-title">Weekly Report</h3>
<span class="Card-subtitle">Feb 3, 2026</span>
</div>
<div class="Card-body">
<p class="Card-text">Revenue increased 12% this week. Customer satisfaction scores remain high at 4.8/5.</p>
</div>
<div class="Card-footer">
<button class="Button Button--tertiary Button--small">Dismiss</button>
<button class="Button Button--primary Button--small">View Details</button>
</div>
</div>

Card with Image

Add images to cards using .Card-image at the top.

Mountain Retreat

Escape to the peaks for a weekend of hiking and relaxation.

<div class="Card" style="max-width: 320px;">
<div class="Card-image" style="background: linear-gradient(135deg, oklch(60% 0.15 250), oklch(50% 0.2 280)); height: 160px;"></div>
<div class="Card-body">
<h3 class="Card-title">Mountain Retreat</h3>
<p class="Card-text">Escape to the peaks for a weekend of hiking and relaxation.</p>
<button class="Button Button--primary Button--small">Book Now</button>
</div>
</div>

Card with Image Overlay

Overlay text on images for hero-style cards.

Featured

Sunset Photography Workshop

Learn to capture golden hour magic

<div class="Card Card--overlay" style="max-width: 400px;">
<div class="Card-image" style="background: linear-gradient(135deg, oklch(45% 0.18 30), oklch(35% 0.15 350)); height: 220px;"></div>
<div class="Card-overlay">
<span class="Card-tag">Featured</span>
<h3 class="Card-title">Sunset Photography Workshop</h3>
<p class="Card-text">Learn to capture golden hour magic</p>
</div>
</div>

Horizontal Card

Side-by-side layout for media and content.

Article

Design Systems at Scale

How leading teams maintain consistency across products.

8 min read
<div class="Card Card--horizontal" style="max-width: 480px;">
<div class="Card-image" style="background: linear-gradient(135deg, oklch(55% 0.12 170), oklch(45% 0.15 200)); min-width: 140px;"></div>
<div class="Card-body">
<span class="Card-tag">Article</span>
<h3 class="Card-title">Design Systems at Scale</h3>
<p class="Card-text">How leading teams maintain consistency across products.</p>
<span class="Card-meta">8 min read</span>
</div>
</div>

Interactive Card

Clickable cards with hover effects.

<a href="#" class="Card Card--interactive" style="max-width: 320px; text-decoration: none;">
<div class="Card-body">
<div style="display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-3);">
<div style="width: 40px; height: 40px; border-radius: var(--r-m); background: oklch(60% 0.15 250); display: flex; align-items: center; justify-content: center;">
<i class="ph ph-folder" style="color: white; font-size: 1.25rem;"></i>
</div>
<div>
<h3 class="Card-title" style="margin: 0;">Design Files</h3>
<span class="Card-meta">24 items</span>
</div>
</div>
<p class="Card-text">Figma files, brand assets, and component libraries.</p>
</div>
</a>

Profile Card

Display user information and quick actions.

Alex Chen

Senior Product Designer

Creating delightful experiences at Acme Corp. Previously at Figma.

<div class="Card" style="max-width: 300px; text-align: center;">
<div class="Card-body">
<div class="Card-avatar" style="width: 80px; height: 80px; border-radius: 50%; background: linear-gradient(135deg, oklch(65% 0.15 150), oklch(55% 0.18 180)); margin: 0 auto var(--space-4);"></div>
<h3 class="Card-title">Alex Chen</h3>
<p class="Card-subtitle">Senior Product Designer</p>
<p class="Card-text" style="margin-top: var(--space-3);">Creating delightful experiences at Acme Corp. Previously at Figma.</p>
<div style="display: flex; gap: var(--space-2); justify-content: center; margin-top: var(--space-4);">
<button class="Button Button--primary Button--small">Follow</button>
<button class="Button Button--secondary Button--small">Message</button>
</div>
</div>
</div>

Stats Card

Highlight key metrics and numbers.

2,847 Total Users +12.5%
$48.2k Revenue +8.2%
94.2% Uptime -0.3%
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); max-width: 600px;">
<div class="Card">
<div class="Card-body" style="text-align: center;">
<span class="Card-stat">2,847</span>
<span class="Card-stat-label">Total Users</span>
<span class="Card-stat-change Card-stat-change--positive">+12.5%</span>
</div>
</div>
<div class="Card">
<div class="Card-body" style="text-align: center;">
<span class="Card-stat">$48.2k</span>
<span class="Card-stat-label">Revenue</span>
<span class="Card-stat-change Card-stat-change--positive">+8.2%</span>
</div>
</div>
<div class="Card">
<div class="Card-body" style="text-align: center;">
<span class="Card-stat">94.2%</span>
<span class="Card-stat-label">Uptime</span>
<span class="Card-stat-change Card-stat-change--negative">-0.3%</span>
</div>
</div>
</div>

Pricing Card

Display pricing tiers and features.

Popular

Pro

$29 /month
  • Unlimited projects
  • 50GB storage
  • Priority support
  • Advanced analytics
  • Custom domain
<div class="Card Card--pricing" style="max-width: 320px;">
<div class="Card-header" style="text-align: center;">
<span class="Card-tag">Popular</span>
<h3 class="Card-title">Pro</h3>
<div class="Card-price">
<span class="Card-price-amount">$29</span>
<span class="Card-price-period">/month</span>
</div>
</div>
<div class="Card-body">
<ul class="Card-features">
<li class="Card-feature">
<i class="ph ph-check"></i>
Unlimited projects
</li>
<li class="Card-feature">
<i class="ph ph-check"></i>
50GB storage
</li>
<li class="Card-feature">
<i class="ph ph-check"></i>
Priority support
</li>
<li class="Card-feature">
<i class="ph ph-check"></i>
Advanced analytics
</li>
<li class="Card-feature Card-feature--disabled">
<i class="ph ph-x"></i>
Custom domain
</li>
</ul>
</div>
<div class="Card-footer">
<button class="Button Button--primary Button--block">Get Started</button>
</div>
</div>

Product Card

E-commerce style product display.

Electronics

Wireless Headphones

(128)
$79.99 $99.99
<div class="Card" style="max-width: 280px;">
<div class="Card-image" style="background: linear-gradient(135deg, oklch(92% 0.02 80), oklch(88% 0.03 60)); height: 200px; position: relative;">
<button class="Card-wishlist" aria-label="Add to wishlist">
<i class="ph ph-heart"></i>
</button>
</div>
<div class="Card-body">
<span class="Card-category">Electronics</span>
<h3 class="Card-title">Wireless Headphones</h3>
<div class="Card-rating">
<i class="ph-fill ph-star"></i>
<i class="ph-fill ph-star"></i>
<i class="ph-fill ph-star"></i>
<i class="ph-fill ph-star"></i>
<i class="ph ph-star"></i>
<span class="Card-rating-count">(128)</span>
</div>
<div class="Card-price-row">
<span class="Card-price-current">$79.99</span>
<span class="Card-price-original">$99.99</span>
</div>
<button class="Button Button--primary Button--block Button--small">Add to Cart</button>
</div>
</div>

Notification Card

Alert or notification style cards.

New Feature Available

Dark mode is now available. Update your preferences in settings.

<div class="Card Card--notification Card--notification-info" style="max-width: 400px;">
<div class="Card-body" style="display: flex; gap: var(--space-3);">
<i class="ph ph-info" style="font-size: 1.25rem; flex-shrink: 0;"></i>
<div>
<h4 class="Card-title" style="margin-bottom: var(--space-1);">New Feature Available</h4>
<p class="Card-text">Dark mode is now available. Update your preferences in settings.</p>
</div>
<button class="Button Button--ghost Button--icon Button--small" aria-label="Dismiss">
<i class="ph ph-x"></i>
</button>
</div>
</div>

Payment Successful

Your subscription has been renewed for another year.

<div class="Card Card--notification Card--notification-success" style="max-width: 400px;">
<div class="Card-body" style="display: flex; gap: var(--space-3);">
<i class="ph ph-check-circle" style="font-size: 1.25rem; flex-shrink: 0;"></i>
<div>
<h4 class="Card-title" style="margin-bottom: var(--space-1);">Payment Successful</h4>
<p class="Card-text">Your subscription has been renewed for another year.</p>
</div>
</div>
</div>

List Card

Cards containing list items.

Recent Activity

  • Document uploaded report-q4.pdf • 2 min ago
  • New team member Sarah joined Design • 1 hour ago
  • Project starred Standard Design System • 3 hours ago
<div class="Card" style="max-width: 360px;">
<div class="Card-header">
<h3 class="Card-title">Recent Activity</h3>
<button class="Button Button--ghost Button--small">View All</button>
</div>
<ul class="Card-list">
<li class="Card-list-item">
<div class="Card-list-icon" style="background: oklch(60% 0.15 150);">
<i class="ph ph-file-text" style="color: white;"></i>
</div>
<div class="Card-list-content">
<span class="Card-list-title">Document uploaded</span>
<span class="Card-list-meta">report-q4.pdf • 2 min ago</span>
</div>
</li>
<li class="Card-list-item">
<div class="Card-list-icon" style="background: oklch(60% 0.15 250);">
<i class="ph ph-user-plus" style="color: white;"></i>
</div>
<div class="Card-list-content">
<span class="Card-list-title">New team member</span>
<span class="Card-list-meta">Sarah joined Design • 1 hour ago</span>
</div>
</li>
<li class="Card-list-item">
<div class="Card-list-icon" style="background: oklch(65% 0.15 45);">
<i class="ph ph-star" style="color: white;"></i>
</div>
<div class="Card-list-content">
<span class="Card-list-title">Project starred</span>
<span class="Card-list-meta">Standard Design System • 3 hours ago</span>
</div>
</li>
</ul>
</div>

Variants

Elevated

Default cards have subtle elevation with shadow.

Elevated Card

Default shadow provides depth.

<div class="Card" style="max-width: 280px;">
<div class="Card-body">
<h3 class="Card-title">Elevated Card</h3>
<p class="Card-text">Default shadow provides depth.</p>
</div>
</div>

Outlined

Border-only variant without shadow.

Outlined Card

Clean border, no shadow.

<div class="Card Card--outlined" style="max-width: 280px;">
<div class="Card-body">
<h3 class="Card-title">Outlined Card</h3>
<p class="Card-text">Clean border, no shadow.</p>
</div>
</div>

Flat

No border or shadow — blends with background.

Flat Card

Minimal visual weight.

<div class="Card Card--flat" style="max-width: 280px;">
<div class="Card-body">
<h3 class="Card-title">Flat Card</h3>
<p class="Card-text">Minimal visual weight.</p>
</div>
</div>

Filled

Filled background without shadow.

Filled Card

Solid background color.

<div class="Card Card--filled" style="max-width: 280px;">
<div class="Card-body">
<h3 class="Card-title">Filled Card</h3>
<p class="Card-text">Solid background color.</p>
</div>
</div>

Padding Sizes

Compact

Less padding

Default

Standard padding

Spacious

More padding

<div style="display: flex; gap: var(--space-4); flex-wrap: wrap;">
<div class="Card Card--compact" style="max-width: 200px;">
<div class="Card-body">
<h4 class="Card-title">Compact</h4>
<p class="Card-text">Less padding</p>
</div>
</div>
<div class="Card" style="max-width: 200px;">
<div class="Card-body">
<h4 class="Card-title">Default</h4>
<p class="Card-text">Standard padding</p>
</div>
</div>
<div class="Card Card--spacious" style="max-width: 200px;">
<div class="Card-body">
<h4 class="Card-title">Spacious</h4>
<p class="Card-text">More padding</p>
</div>
</div>
</div>

Card Grid

Responsive grid layout for multiple cards.

Card One

Description text for the first card.

Card Two

Description text for the second card.

Card Three

Description text for the third card.

<div class="CardGrid">
<div class="Card">
<div class="Card-image" style="background: linear-gradient(135deg, oklch(60% 0.15 30), oklch(50% 0.18 10)); height: 120px;"></div>
<div class="Card-body">
<h3 class="Card-title">Card One</h3>
<p class="Card-text">Description text for the first card.</p>
</div>
</div>
<div class="Card">
<div class="Card-image" style="background: linear-gradient(135deg, oklch(60% 0.15 150), oklch(50% 0.18 170)); height: 120px;"></div>
<div class="Card-body">
<h3 class="Card-title">Card Two</h3>
<p class="Card-text">Description text for the second card.</p>
</div>
</div>
<div class="Card">
<div class="Card-image" style="background: linear-gradient(135deg, oklch(60% 0.15 250), oklch(50% 0.18 270)); height: 120px;"></div>
<div class="Card-body">
<h3 class="Card-title">Card Three</h3>
<p class="Card-text">Description text for the third card.</p>
</div>
</div>
</div>

Common Patterns

Dashboard Cards

1,284 Active Users +5.2%
$32.1k Monthly Revenue +11%
98.7% Uptime -0.1%
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); max-width: 700px;">
<div class="Card">
<div class="Card-body" style="text-align: center;">
<span class="Card-stat">1,284</span>
<span class="Card-stat-label">Active Users</span>
<span class="Card-stat-change Card-stat-change--positive">+5.2%</span>
</div>
</div>
<div class="Card">
<div class="Card-body" style="text-align: center;">
<span class="Card-stat">$32.1k</span>
<span class="Card-stat-label">Monthly Revenue</span>
<span class="Card-stat-change Card-stat-change--positive">+11%</span>
</div>
</div>
<div class="Card">
<div class="Card-body" style="text-align: center;">
<span class="Card-stat">98.7%</span>
<span class="Card-stat-label">Uptime</span>
<span class="Card-stat-change Card-stat-change--negative">-0.1%</span>
</div>
</div>
</div>

Card in a Settings Page

Notifications

Email notifications
Push notifications
<div class="Card Card--outlined" style="max-width: 480px;">
<div class="Card-header">
<h3 class="Card-title">Notifications</h3>
</div>
<div class="Card-body">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--space-3);">
<span>Email notifications</span>
<label class="Toggle"><input type="checkbox" checked><span class="Toggle-slider"></span></label>
</div>
<div style="display: flex; justify-content: space-between; align-items: center;">
<span>Push notifications</span>
<label class="Toggle"><input type="checkbox"><span class="Toggle-slider"></span></label>
</div>
</div>
</div>

Trip Photos

12 photos · June 2025

<div class="Card" style="max-width: 360px;">
<div class="Card-body">
<h3 class="Card-title">Trip Photos</h3>
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2); margin-top: var(--space-3);">
<div style="aspect-ratio: 1; background: linear-gradient(135deg, oklch(60% 0.15 30), oklch(50% 0.18 10)); border-radius: var(--r-s);"></div>
<div style="aspect-ratio: 1; background: linear-gradient(135deg, oklch(60% 0.15 150), oklch(50% 0.18 170)); border-radius: var(--r-s);"></div>
<div style="aspect-ratio: 1; background: linear-gradient(135deg, oklch(60% 0.15 250), oklch(50% 0.18 270)); border-radius: var(--r-s);"></div>
</div>
<p class="Card-meta" style="margin-top: var(--space-2);">12 photos · June 2025</p>
</div>
</div>

Card as Empty State

No projects yet

Create your first project to get started.

<div class="Card Card--outlined" style="max-width: 400px; text-align: center;">
<div class="Card-body" style="padding: var(--space-8);">
<i class="ph ph-folder-open" style="font-size: 2.5rem; color: var(--fg-3); margin-bottom: var(--space-3);"></i>
<h3 class="Card-title">No projects yet</h3>
<p class="Card-text">Create your first project to get started.</p>
<button class="Button Button--primary Button--small" style="margin-top: var(--space-4);">Create Project</button>
</div>
</div>

Customization

Override card styles using CSS custom properties:

/* Custom card background */
.Card--custom {
  --card-bg: oklch(95% 0.02 250);
  --card-border: oklch(85% 0.05 250);
  background-color: var(--card-bg);
  border-color: var(--card-border);
}

/* Custom shadow depth */
.Card--deep {
  box-shadow: 
    0 4px 6px -1px oklch(0% 0 0 / 0.1),
    0 10px 15px -3px oklch(0% 0 0 / 0.1);
}

/* Custom border radius */
.Card--rounded {
  border-radius: var(--space-6);
}

/* Custom padding */
.Card--tight {
  --card-padding: var(--space-3);
}

.Card--loose {
  --card-padding: var(--space-8);
}

/* Accent border */
.Card--accent {
  border-left: 4px solid var(--accent);
}

Theme Variants

/* Success card */
.Card--success {
  --card-bg: oklch(95% 0.04 150);
  --card-border: oklch(70% 0.15 150);
  border-left: 4px solid var(--card-border);
}

/* Warning card */
.Card--warning {
  --card-bg: oklch(95% 0.04 85);
  --card-border: oklch(75% 0.15 85);
  border-left: 4px solid var(--card-border);
}

/* Error card */
.Card--error {
  --card-bg: oklch(95% 0.04 25);
  --card-border: oklch(65% 0.2 25);
  border-left: 4px solid var(--card-border);
}

API Reference

Base Classes

Class Description
.Card Base card container (required)

Structure Classes

Class Description
.Card-header Card header section with title and actions
.Card-body Main content area with padding
.Card-footer Footer section for actions
.Card-image Image container at card top
.Card-overlay Text overlay on images

Typography Classes

Class Description
.Card-title Card heading text
.Card-subtitle Secondary heading or date
.Card-text Body text content
.Card-meta Metadata like timestamps or counts
.Card-tag Category or status tag
.Card-category Product/content category label

Variant Classes

Class Description
.Card--outlined Border only, no shadow
.Card--flat No border or shadow
.Card--filled Filled background, no shadow
.Card--interactive Clickable with hover effects
.Card--horizontal Side-by-side layout
.Card--overlay Text overlaid on image
.Card--pricing Pricing tier styling

Size Classes

Class Description
.Card--compact Reduced padding
.Card--spacious Increased padding

Stats Classes

Class Description
.Card-stat Large metric number
.Card-stat-label Metric label text
.Card-stat-change Change indicator
.Card-stat-change--positive Positive change (green)
.Card-stat-change--negative Negative change (red)

Pricing Classes

Class Description
.Card-price Price container
.Card-price-amount Large price number
.Card-price-period Billing period text
.Card-features Feature list container
.Card-feature Individual feature item
.Card-feature--disabled Unavailable feature (grayed)

Product Classes

Class Description
.Card-wishlist Wishlist heart button
.Card-rating Star rating container
.Card-rating-count Review count text
.Card-price-current Current sale price
.Card-price-original Original strikethrough price

Notification Classes

Class Description
.Card--notification Notification card base
.Card--notification-info Info notification (blue)
.Card--notification-success Success notification (green)
.Card--notification-warning Warning notification (yellow)
.Card--notification-error Error notification (red)

List Classes

Class Description
.Card-list List container inside card
.Card-list-item Individual list item
.Card-list-icon Icon container for list item
.Card-list-content Text content wrapper
.Card-list-title List item title
.Card-list-meta List item metadata

Layout Classes

Class Description
.CardGrid Responsive card grid container

CSS Reference

/* Base card */
.Card {
  background: var(--bg);
  border: 1px solid var(--bd);
  border-radius: var(--r-m);
  box-shadow: 0 1px 3px oklch(0% 0 0 / 0.08);
  overflow: hidden;
}

/* Structure */
.Card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4);
  border-bottom: 1px solid var(--bd);
}

.Card-body {
  padding: var(--space-4);
}

.Card-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-4);
  border-top: 1px solid var(--bd);
}

.Card-image {
  width: 100%;
  background-size: cover;
  background-position: center;
}

/* Typography */
.Card-title {
  font-weight: 600;
  font-size: 1rem;
  color: var(--fg);
  margin-bottom: var(--space-1);
}

.Card-subtitle {
  font-size: 0.85rem;
  color: var(--fg-3);
}

.Card-text {
  font-size: 0.9rem;
  color: var(--fg-2);
  line-height: 1.5;
}

.Card-meta {
  font-size: 0.8rem;
  color: var(--fg-3);
}

.Card-tag {
  display: inline-block;
  padding: 2px var(--space-2);
  font-size: 0.75rem;
  font-weight: 600;
  border-radius: var(--r-s);
  background: var(--accent);
  color: white;
}

/* Variants */
.Card--outlined {
  box-shadow: none;
}

.Card--flat {
  border: none;
  box-shadow: none;
  background: transparent;
}

.Card--filled {
  box-shadow: none;
  background: var(--bg-s);
}

.Card--interactive {
  cursor: pointer;
  transition: box-shadow 0.15s, transform 0.15s;
}

.Card--interactive:hover {
  box-shadow: 0 4px 12px oklch(0% 0 0 / 0.12);
  transform: translateY(-2px);
}

.Card--horizontal {
  display: flex;
}

.Card--horizontal .Card-image {
  width: auto;
  min-width: 140px;
}

/* Overlay */
.Card--overlay {
  position: relative;
}

.Card--overlay .Card-overlay {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: var(--space-4);
  background: linear-gradient(to top, oklch(0% 0 0 / 0.7), transparent);
  color: white;
}

.Card--overlay .Card-title,
.Card--overlay .Card-text {
  color: white;
}

/* Sizes */
.Card--compact .Card-body,
.Card--compact .Card-header,
.Card--compact .Card-footer {
  padding: var(--space-2) var(--space-3);
}

.Card--spacious .Card-body,
.Card--spacious .Card-header,
.Card--spacious .Card-footer {
  padding: var(--space-6);
}

/* Stats */
.Card-stat {
  display: block;
  font-size: 1.75rem;
  font-weight: 700;
  color: var(--fg);
}

.Card-stat-label {
  display: block;
  font-size: 0.8rem;
  color: var(--fg-3);
  margin-top: var(--space-1);
}

.Card-stat-change {
  display: block;
  font-size: 0.8rem;
  font-weight: 600;
  margin-top: var(--space-1);
}

.Card-stat-change--positive { color: oklch(55% 0.15 150); }
.Card-stat-change--negative { color: oklch(55% 0.2 25); }

/* Pricing */
.Card-price-amount {
  font-size: 2rem;
  font-weight: 700;
}

.Card-price-period {
  font-size: 0.85rem;
  color: var(--fg-3);
}

.Card-features {
  list-style: none;
  padding: 0;
  margin: 0;
}

.Card-feature {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) 0;
}

.Card-feature--disabled {
  color: var(--fg-3);
  text-decoration: line-through;
}

/* Product */
.Card-wishlist {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  background: white;
  border: none;
  border-radius: 50%;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 1px 3px oklch(0% 0 0 / 0.15);
}

.Card-rating {
  display: flex;
  align-items: center;
  gap: 2px;
  color: oklch(70% 0.15 80);
  margin: var(--space-2) 0;
}

.Card-rating-count {
  font-size: 0.8rem;
  color: var(--fg-3);
  margin-left: var(--space-1);
}

.Card-price-current {
  font-weight: 700;
  font-size: 1.1rem;
}

.Card-price-original {
  text-decoration: line-through;
  color: var(--fg-3);
  font-size: 0.9rem;
  margin-left: var(--space-2);
}

/* Notification */
.Card--notification {
  border-left: 4px solid var(--bd);
}

.Card--notification-info { border-left-color: oklch(60% 0.15 250); }
.Card--notification-success { border-left-color: oklch(55% 0.15 150); }
.Card--notification-warning { border-left-color: oklch(70% 0.15 80); }
.Card--notification-error { border-left-color: oklch(55% 0.2 25); }

/* List */
.Card-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.Card-list-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--bd);
}

.Card-list-icon {
  width: 32px;
  height: 32px;
  border-radius: var(--r-s);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.Card-list-title {
  display: block;
  font-weight: 500;
  font-size: 0.9rem;
}

.Card-list-meta {
  display: block;
  font-size: 0.8rem;
  color: var(--fg-3);
}

/* Grid */
.CardGrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-4);
}

Accessibility

Semantic Structure

<!-- Use article for standalone content -->
<article class="Card">
    <div class="Card-body">
        <h3 class="Card-title">Article Title</h3>
        <p class="Card-text">Self-contained content.</p>
    </div>
</article>

<!-- Use heading hierarchy -->
<div class="Card">
    <div class="Card-header">
        <h2 class="Card-title">Section Title</h2>
    </div>
    <div class="Card-body">
        <h3>Subsection</h3>
        <p class="Card-text">Content under subsection.</p>
    </div>
</div>

Interactive Cards

<!-- Clickable card as link -->
<a href="/project" class="Card Card--interactive">
    <div class="Card-body">
        <h3 class="Card-title">Project Name</h3>
        <p class="Card-text">Click to view project details.</p>
    </div>
</a>

<!-- Card with multiple actions — don't make whole card clickable -->
<div class="Card">
    <div class="Card-body">
        <h3 class="Card-title">Project Name</h3>
        <p class="Card-text">Project description here.</p>
        <div class="Card-actions">
            <a href="/project/edit">Edit</a>
            <button>Delete</button>
        </div>
    </div>
</div>

Images

<!-- Decorative image -->
<div class="Card">
    <div class="Card-image" role="presentation" aria-hidden="true"
         style="background-image: url('pattern.jpg');"></div>
    <div class="Card-body">
        <h3 class="Card-title">Title</h3>
    </div>
</div>

<!-- Meaningful image -->
<div class="Card">
    <img class="Card-image" src="product.jpg" 
         alt="Blue wireless headphones with cushioned ear cups">
    <div class="Card-body">
        <h3 class="Card-title">Wireless Headphones</h3>
    </div>
</div>

Keyboard Navigation

Key Action
Tab Move focus to interactive elements
Enter Activate focused link or button
Space Activate focused button

Screen Reader Considerations

<!-- Price with context -->
<div class="Card-price-row">
    <span class="Card-price-current" aria-label="Sale price: $79.99">$79.99</span>
    <span class="Card-price-original" aria-label="Original price: $99.99">
        <s>$99.99</s>
    </span>
</div>

<!-- Stats with labels -->
<div class="Card-body">
    <span class="Card-stat" aria-describedby="stat-label-users">2,847</span>
    <span class="Card-stat-label" id="stat-label-users">Total Users</span>
</div>

<!-- Rating with text alternative -->
<div class="Card-rating" aria-label="4 out of 5 stars, 128 reviews">
    <i class="ph-fill ph-star" aria-hidden="true"></i>
    <i class="ph-fill ph-star" aria-hidden="true"></i>
    <i class="ph-fill ph-star" aria-hidden="true"></i>
    <i class="ph-fill ph-star" aria-hidden="true"></i>
    <i class="ph ph-star" aria-hidden="true"></i>
    <span class="Card-rating-count">(128)</span>
</div>

Best Practices

Do

  • Use consistent card heights in grids — align content or use CSS Grid
  • Limit content — Cards should be scannable, not essays
  • Single primary action — One clear CTA per card
  • Meaningful images — Images should add value, not just decoration
  • Clear visual hierarchy — Title → Supporting text → Actions
  • Group related cards — Use grids with consistent spacing

Don’t

  • Nest cards — Cards inside cards creates visual confusion
  • Too many actions — More than 2-3 actions clutters the card
  • Walls of text — Keep descriptions to 2-3 lines max
  • Inconsistent styling — Mix variants sparingly within a view
  • Click the whole card with multiple CTAs — Accessibility nightmare
  • Tiny touch targets — Ensure buttons/links are at least 44px

Content Guidelines

Titles: Keep to one line when possible. Be specific.

  • ✓ “Q4 Revenue Report”
  • ✗ “Report”

Descriptions: Front-load important info. Truncate gracefully.

  • ✓ “Revenue increased 12% driven by new enterprise clients.”
  • ✗ “In this quarter we saw various changes across multiple metrics…”

Actions: Use clear, specific verbs.

  • ✓ “View Report”, “Add to Cart”, “Start Trial”
  • ✗ “Click Here”, “Submit”, “Go”