Skip to main content
โšก Calmops

Card Design Patterns: Modern UI Components

Cards are versatile UI components that group related content and actions. They’re fundamental to modern web design, appearing in dashboards, e-commerce, content feeds, and more. This guide covers card design patterns and implementation.

Basic Card Structure

Simple Card

<article class="card">
  <div class="card-content">
    <h3 class="card-title">Card Title</h3>
    <p class="card-description">
      This is the main content of the card. It can contain multiple paragraphs
      or other HTML elements.
    </p>
  </div>
</article>
.card {
  background: white;
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  overflow: hidden;
}

.card-content {
  padding: 1.25rem;
}

.card-title {
  font-size: 1.125rem;
  font-weight: 600;
  color: #111827;
  margin: 0 0 0.5rem;
}

.card-description {
  font-size: 0.9375rem;
  color: #6b7280;
  line-height: 1.5;
  margin: 0;
}

Card with Image

Image Top

<article class="card">
  <div class="card-image">
    <img src="image.jpg" alt="Card image" loading="lazy">
  </div>
  <div class="card-content">
    <span class="card-category">Category</span>
    <h3 class="card-title">Card Title</h3>
    <p class="card-description">Description text...</p>
    <div class="card-meta">
      <span>5 min read</span>
    </div>
  </div>
</article>
.card-image {
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

.card-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}

.card:hover .card-image img {
  transform: scale(1.05);
}

.card-category {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #2563eb;
  margin-bottom: 0.5rem;
}

.card-meta {
  display: flex;
  gap: 1rem;
  font-size: 0.8125rem;
  color: #9ca3af;
  margin-top: 1rem;
}

Image Overlay

.card-overlay {
  position: relative;
}

.card-overlay .card-image {
  position: absolute;
  inset: 0;
}

.card-overlay .card-content {
  position: relative;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
  color: white;
  padding-top: 50%;
}

.card-overlay .card-title {
  color: white;
}

.card-overlay .card-description {
  color: rgba(255, 255, 255, 0.8);
}

Card with Actions

Action Buttons

<article class="card">
  <div class="card-content">
    <h3 class="card-title">Card Title</h3>
    <p class="card-description">Description...</p>
  </div>
  <div class="card-actions">
    <button class="btn btn-secondary btn-sm">Learn More</button>
    <button class="btn btn-primary btn-sm">Get Started</button>
  </div>
</article>
.card-actions {
  display: flex;
  gap: 0.5rem;
  padding: 0.75rem 1.25rem 1.25rem;
  border-top: 1px solid #f3f4f6;
  margin-top: 0.5rem;
}

.card-actions .btn {
  flex: 1;
}

Icon Actions

<article class="card">
  <div class="card-content">
    <div class="card-icon">
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
        <path d="M12 2L2 7l10 5 10-5-10-5z" />
      </svg>
    </div>
    <h3 class="card-title">Feature Card</h3>
    <p class="card-description">Description...</p>
  </div>
</article>
.card-icon {
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #eff6ff;
  color: #2563eb;
  border-radius: 12px;
  margin-bottom: 1rem;
}

.card-icon svg {
  width: 24px;
  height: 24px;
}

Card Variations

Interactive Card

.card-interactive {
  cursor: pointer;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.card-interactive:hover {
  transform: translateY(-4px);
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
}

.card-interactive:active {
  transform: translateY(-2px);
}

Selectable Card

.card-selectable {
  cursor: pointer;
  border: 2px solid transparent;
  transition: border-color 0.2s, background 0.2s;
}

.card-selectable:hover {
  border-color: #d1d5db;
}

.card-selectable.selected {
  border-color: #2563eb;
  background: #eff6ff;
}

.card-selectable input[type="checkbox"],
.card-selectable input[type="radio"] {
  position: absolute;
  opacity: 0;
}

Stat Card

.card-stat {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.card-stat .stat-value {
  font-size: 2rem;
  font-weight: 700;
  color: #111827;
}

.card-stat .stat-label {
  font-size: 0.875rem;
  color: #6b7280;
}

.card-stat .stat-change {
  font-size: 0.8125rem;
  font-weight: 500;
}

.card-stat .stat-change.positive {
  color: #10b981;
}

.card-stat .stat-change.negative {
  color: #ef4444;
}

Card Grid Layouts

Responsive Grid

.card-grid {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: repeat(1, 1fr);
}

@media (min-width: 640px) {
  .card-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .card-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 1280px) {
  .card-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

Auto-Fit Grid

.card-grid-auto {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.5rem;
}

Masonry Layout (CSS Columns)

.card-grid-masonry {
  column-count: 1;
  column-gap: 1.5rem;
}

.card-grid-masonry .card {
  break-inside: avoid;
  margin-bottom: 1.5rem;
}

@media (min-width: 640px) {
  .card-grid-masonry {
    column-count: 2;
  }
}

@media (min-width: 1024px) {
  .card-grid-masonry {
    column-count: 3;
  }
}

Card Patterns by Use Case

Product Card

<article class="card product-card">
  <div class="product-image">
    <img src="product.jpg" alt="Product name">
    <span class="product-badge">Sale</span>
  </div>
  <div class="product-content">
    <span class="product-category">Category</span>
    <h3 class="product-title">Product Name</h3>
    <div class="product-rating">โ˜…โ˜…โ˜…โ˜…โ˜† (4.2)</div>
    <div class="product-price">
      <span class="price-current">$49.99</span>
      <span class="price-original">$79.99</span>
    </div>
    <button class="btn btn-primary btn-block">Add to Cart</button>
  </div>
</article>

User Card

<article class="card user-card">
  <div class="user-avatar">
    <img src="avatar.jpg" alt="User name">
  </div>
  <div class="user-content">
    <h3 class="user-name">John Doe</h3>
    <p class="user-title">Senior Developer</p>
    <p class="user-bio">Building great products...</p>
    <div class="user-stats">
      <span><strong>120</strong> Posts</span>
      <span><strong>2.5k</strong> Followers</span>
    </div>
  </div>
  <div class="user-actions">
    <button class="btn btn-primary btn-sm">Follow</button>
    <button class="btn btn-secondary btn-sm">Message</button>
  </div>
</article>

Notification Card

<div class="card notification-card">
  <div class="notification-icon">
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
      <path d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
    </svg>
  </div>
  <div class="notification-content">
    <p class="notification-message">
      <strong>Sarah</strong> mentioned you in a comment
    </p>
    <span class="notification-time">2 minutes ago</span>
  </div>
</div>

Card Elevation

Shadow Levels

.card-shadow-sm {
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}

.card-shadow-md {
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.07), 0 2px 4px rgba(0, 0, 0, 0.05);
}

.card-shadow-lg {
  box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05);
}

.card-shadow-xl {
  box-shadow: 0 20px 25px rgba(0, 0, 0, 0.1), 0 10px 10px rgba(0, 0, 0, 0.04);
}

/* Interactive elevation */
.card-interactive.card-shadow-sm:hover {
  box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
}

Border Variant

.card-border {
  border: 1px solid #e5e7eb;
  box-shadow: none;
}

.card-border:hover {
  border-color: #d1d5db;
}

Mobile Considerations

@media (max-width: 640px) {
  .card-content {
    padding: 1rem;
  }
  
  .card-actions {
    padding: 0.75rem 1rem 1rem;
    flex-direction: column;
  }
  
  .card-grid {
    gap: 1rem;
  }
}

Accessibility

<!-- Clickable card with proper semantics -->
<article 
  class="card card-interactive" 
  tabindex="0" 
  role="button"
  aria-label="Article: Card Title"
>
  <div class="card-image">
    <img src="image.jpg" alt="">
  </div>
  <div class="card-content">
    <h3 class="card-title">Card Title</h3>
  </div>
</article>
.card-interactive:focus-visible {
  outline: 2px solid #2563eb;
  outline-offset: 2px;
}

Best Practices

Do

  • Use consistent padding
  • Include clear visual hierarchy
  • Add hover/focus states
  • Use meaningful images
  • Keep text concise

Don’t

  • Overcrowd cards
  • Use inconsistent sizes
  • Forget mobile layouts
  • Skip alt text
  • Make cards too complex

Summary

Cards are versatile building blocks:

  • Basic: Content + optional image
  • Actions: Buttons, links, icons
  • Interactive: Hover effects, selection
  • Grid: Responsive layouts
  • Types: Product, user, notification, stat

Key implementation tips:

  • Consistent spacing
  • Clear hierarchy
  • Interactive feedback
  • Mobile responsive
  • Accessible markup

Use cards thoughtfully - they’re everywhere in modern UI!

Comments