Skill

Generate Card-Based UI Components and Layouts

Design-style skill for Card-Based Design: self-contained, responsive content cards with clear boundaries and consistent structure.


79
Spark score
out of 100
Updated 25 days ago
Version 13.6.1

Add to Favorites

Why it matters

Design and implement card-based user interfaces that organize content into modular, scannable containers with consistent visual hierarchy and responsive behavior across devices.

Outcomes

What it gets done

01

Generate semantic HTML markup for card components with proper accessibility attributes

02

Create CSS layouts using grid or flexbox for responsive card arrangements

03

Structure card content with headers, images, metadata, and action elements

04

Implement card interaction patterns including hover states, shadows, and click targets

Install

Add it to your toolbox

Run in your project directory:

curl -fsSL https://spark.entire.vc/get/ag-card-based-design | bash

Overview

Card-Based Design

A design-style skill for Card-Based Design - self-contained, responsive content cards with clear visual boundaries - with matching Web CSS Grid and SwiftUI implementations. Use it for feeds, product grids, or article listings presenting many discrete items that need consistent, scannable visual structure across screen sizes.

What it does

Card-Based Design is a design-style child skill ('bite-sized consumption - encapsulating discrete pieces of information into distinct visual containers'), part of the design-it family and not meant to be triggered directly. Three core principles: Encapsulation (every card is self-contained, with an image, title, short description, and usually an action like a button or a 'like' icon), Responsive Flow (cards easily reflow across screen sizes, from a 4-column desktop grid down to a single mobile column), and Clear Boundaries (cards must visually pop off the background).

When to use - and when NOT to

Use it when the user's request matches this modular, scannable content-container aesthetic - feeds, product grids, article listings, or any UI presenting many discrete items that need consistent visual structure. As a design sub-style, it's selected by the parent design-it skill's routing rather than invoked on its own.

Inputs and outputs

Visual DNA is very flexible on color, but the background should be slightly darker or distinct from the card color - Sophisticated Neutral works well for a premium feel - with clear typographic hierarchy inside each card (header, subheader, body) and standard border-radius: 8px with a medium drop shadow. The web implementation uses CSS Grid with auto-fit/auto-fill for automatic responsiveness (grid-template-columns: repeat(auto-fill, minmax(300px, 1fr))), each card as a flex column with overflow: hidden to keep images inside rounded corners, a subtle shadow that deepens and lifts the card (transform: translateY(-4px)) on hover, an object-fit: cover image area, flexible content padding that pushes a footer to the bottom via flex-grow: 1, and a bordered footer row for actions.

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 24px;
}
.card:hover { transform: translateY(-4px); box-shadow: 0 8px 24px rgba(0,0,0,0.12); }

The body background is typically a standard app gray (#f0f2f5) so white cards read as distinct, elevated surfaces rather than blending into the page.

Integrations

SwiftUI reproduces the same card anatomy - a gray placeholder image Rectangle, a content VStack with headline title and a two-line-limited secondary-color description, cornerRadius(12), and a clean subtle drop shadow (shadow(color: .black.opacity(0.08), radius: 12, x: 0, y: 4)) - matching the web card's visual weight and structure in a native idiom.

Who it's for

Designers and developers building a feed, product grid, or article listing that needs consistent, self-contained, responsive content containers - the default pattern for presenting many discrete items scannable at a glance, on any screen size, without every item needing bespoke layout treatment.

Source README

Card-Based Design

"Bite-sized consumption. Encapsulating discrete pieces of information into distinct visual containers."

When to Use

Use this sub-style when the user's request matches the aesthetic described above. This is a child reference of the design-it skill and is not meant to be triggered directly.

Core Principles

  1. Encapsulation: Every card is self-contained. It has an image, a title, a short description, and usually an action (like a button or a 'like' icon).
  2. Responsive Flow: Cards easily reflow on different screen sizes (from a 4-column grid on desktop to a single column on mobile).
  3. Clear Boundaries: Cards must visually pop off the background.

Visual DNA

  • Colors: Very flexible. The background should be slightly darker or distinct from the card color. Sophisticated Neutral works well for a premium feel.
  • Typography: Clear hierarchy within the card (Header, Subheader, Body).
  • Styling: Standard border-radius: 8px and a medium drop shadow.

Web Implementation

  • CSS Grid with auto-fit or a Masonry layout.
  • CSS Example:
body {
  background-color: #f0f2f5; /* Standard app background */
  padding: 40px;
}

.card-grid {
  display: grid;
  /* Auto-responsive magic */
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 24px;
}

.card {
  background: #ffffff;
  border-radius: 12px;
  overflow: hidden; /* Keep images inside the rounded corners */
  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
  transition: transform 0.2s, box-shadow 0.2s;
  display: flex;
  flex-direction: column;
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}

.card-image {
  width: 100%;
  height: 200px;
  object-fit: cover;
  border-bottom: 1px solid #eee;
}

.card-content {
  padding: 20px;
  flex-grow: 1; /* Pushes footer to the bottom */
}

.card-footer {
  padding: 16px 20px;
  border-top: 1px solid #eee;
  display: flex;
  justify-content: space-between;
}

App Implementation

SwiftUI

struct ContentCard: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 0) {
            // Image Area
            Rectangle()
                .fill(Color.gray.opacity(0.2))
                .frame(height: 160)
            
            // Content Area
            VStack(alignment: .leading, spacing: 8) {
                Text("Card Title")
                    .font(.headline)
                Text("A brief description of the content inside this discrete card container.")
                    .font(.subheadline)
                    .foregroundColor(.secondary)
                    .lineLimit(2)
            }
            .padding(16)
        }
        .background(Color.white)
        .cornerRadius(12)
        // Clean, subtle drop shadow
        .shadow(color: Color.black.opacity(0.08), radius: 12, x: 0, y: 4)
    }
}

// In your view:
// LazyVGrid(columns: [GridItem(.adaptive(minimum: 160), spacing: 16)]) { ... }
  • VStack inside a background with .cornerRadius and .shadow is the standard.
  • Use LazyVGrid with .adaptive(minimum: 160) to automatically create a multi-column card grid that flows perfectly on iPad or iPhone.

Flutter

class ContentCard extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Card(
      elevation: 4, // Handles shadow natively
      shadowColor: Colors.black.withOpacity(0.4),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      clipBehavior: Clip.antiAlias, // Critical: stops images from bleeding over corners
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: [
          // Image Area
          Container(
            height: 160,
            color: Colors.grey[300],
            width: double.infinity,
          ),
          // Content Area
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: const [
                Text('Card Title', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
                SizedBox(height: 8),
                Text(
                  'A brief description of the content inside this discrete card container.',
                  style: TextStyle(color: Colors.black54),
                  maxLines: 2,
                  overflow: TextOverflow.ellipsis,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
// In your view: Use GridView.builder for the layout
  • The native Card widget does almost all the heavy lifting.
  • Critical fix: You must set clipBehavior: Clip.antiAlias on the Card, otherwise the top corners of your images will peek outside the border radius.

React Native

const ContentCard = () => {
  return (
    <View style={styles.card}>
      <View style={styles.imageArea} />
      <View style={styles.contentArea}>
        <Text style={styles.title}>Card Title</Text>
        <Text style={styles.description} numberOfLines={2}>
          A brief description of the content inside this discrete card container.
        </Text>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  card: {
    backgroundColor: '#FFF',
    borderRadius: 12,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 4 },
    shadowOpacity: 0.08,
    shadowRadius: 12,
    elevation: 4,
    margin: 8,
    overflow: 'hidden', // Keeps image inside borders
  },
  imageArea: {
    height: 160,
    backgroundColor: '#E0E0E0',
  },
  contentArea: {
    padding: 16,
  },
  title: {
    fontSize: 18,
    fontWeight: '600',
    marginBottom: 8,
  },
  description: {
    color: '#666',
  }
});
// In your view: <FlatList numColumns={2} data={data} renderItem={...} />
  • Wrap everything in a View with borderRadius and overflow: 'hidden'.
  • elevation: 4 provides the drop shadow on Android, while the shadow* props handle iOS.
  • For a Pinterest/Masonry style (columns of different heights), you must use a third-party library like react-native-masonry-list, as FlatList cannot do varying row heights in columns.

Jetpack Compose

@Composable
fun ContentCard() {
    // ElevatedCard provides the shadow and shape natively
    ElevatedCard(
        elevation = CardDefaults.elevatedCardElevation(defaultElevation = 4.dp),
        shape = RoundedCornerShape(12.dp),
        colors = CardDefaults.elevatedCardColors(containerColor = Color.White),
        modifier = Modifier.fillMaxWidth().padding(8.dp)
    ) {
        Column {
            // Image Area
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(160.dp)
                    .background(Color.LightGray)
            )
            
            // Content Area
            Column(modifier = Modifier.padding(16.dp)) {
                Text(
                    text = "Card Title",
                    style = MaterialTheme.typography.titleMedium,
                    fontWeight = FontWeight.Bold
                )
                Spacer(Modifier.height(8.dp))
                Text(
                    text = "A brief description of the content inside this discrete card container.",
                    style = MaterialTheme.typography.bodyMedium,
                    color = Color.Gray,
                    maxLines = 2,
                    overflow = TextOverflow.Ellipsis
                )
            }
        }
    }
}
// In your view: LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 160.dp)) { ... }
  • ElevatedCard is the perfect Material 3 component for this. It handles clipping and shadows automatically.
  • Use GridCells.Adaptive(minSize = 160.dp) in a LazyVerticalGrid to achieve an auto-flowing grid identical to CSS Grid auto-fit.

Do's and Don'ts

  • DO: Make the entire card clickable, not just the title or image.
  • DON'T: Put too much text in a card. If the user has to scroll within a card, the card is too big.

Limitations

  • This is a styling reference and does not replace environment-specific validation, accessibility testing, or expert review.
  • Ensure appropriate contrast ratios and responsive behaviors are verified separately.

FAQ

Common questions

Discussion

Questions & comments ยท 0

Sign In Sign in to leave a comment.