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>
Card with Header and Footer
Use header and footer sections for titles, metadata, and actions.
Weekly Report
Feb 3, 2026Revenue 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.
<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.
Design Systems at Scale
How leading teams maintain consistency across products.
<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.
<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.
Pro
- 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.
Wireless Headphones
<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
-
New team member
-
Project starred
<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
<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
<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>
Card with Media Gallery
Trip Photos
<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”