DBMS Topics
Building a Card Component
title: "Building a Card Component",
Cards package content into neat, self-contained boxes. They're everywhere in modern UI — feature grids, team pages, link collections, content previews. In MDX, they let you break out of the plain-text look and present information visually.
Why Cards in MDX?
Markdown gives you headings, paragraphs, and lists. Sometimes that's not enough. You need visual grouping, clear boundaries between items, and a layout that feels polished. Cards do that. They take your docs from "wall of text" to "organized product page."
Component Source Code
Here's the full Card system with sub-components for header, body, footer, image, and grid:
Basic Card Usage in MDX
Here's a simple card with header, body, and footer:
import { Card, CardHeader, CardBody, CardFooter } from '../components/Card';
# Feature Overview
<Card>
<CardHeader>
## Getting Started
</CardHeader>
<CardBody>
Learn how to set up your development environment and create
your first MDX-powered application in under 5 minutes.
</CardBody>
<CardFooter>
**Estimated time:** 5 minutes
</CardFooter>
</Card>Card with Image
Add a hero image at the top:
import { Card, CardImage, CardBody } from '../components/Card';
<Card variant="elevated">
<CardImage
src="/images/tutorial-hero.jpg"
alt="Screenshot of the completed tutorial project"
/>
<CardBody>
## Complete Tutorial
Build a full documentation site from scratch using MDX,
Next.js, and Tailwind CSS.
</CardBody>
</Card>Card Grid Layout
CardGrid arranges cards into a responsive grid — stacks on mobile, fills columns on desktop:
import { Card, CardBody, CardGrid } from '../components/Card';
# Our Features
<CardGrid columns={3}>
<Card variant="outlined">
<CardBody>
### ⚡ Fast
Lightning-fast builds with incremental compilation
and smart caching strategies.
</CardBody>
</Card>
<Card variant="outlined">
<CardBody>
### 🔐 Secure
Built-in security best practices with automatic
vulnerability scanning.
</CardBody>
</Card>
<Card variant="outlined">
<CardBody>
### 📱 Responsive
Mobile-first design that looks great on every
device and screen size.
</CardBody>
</Card>
</CardGrid>Card Variants
Elevated Card (Default)
Uses box shadows for a "floating" look. Shadow deepens on hover:
<Card variant="elevated">
<CardBody>
This card appears to float above the page with a subtle shadow
that intensifies on hover.
</CardBody>
</Card>Outlined Card
Borders instead of shadows. Flatter, more minimal:
<Card variant="outlined">
<CardBody>
This card has a visible border and transparent background.
On hover, the border color transitions to blue.
</CardBody>
</Card>Filled Card
Subtle background color to stand out from the page:
<Card variant="filled">
<CardBody>
This card has a light gray background that differentiates
it from the surrounding content.
</CardBody>
</Card>Clickable Cards (Link Cards)
Pass href to make the whole card a link:
<CardGrid columns={2}>
<Card href="/docs/getting-started" variant="outlined">
<CardBody>
### 📖 Documentation
Full guides and API references for every feature.
</CardBody>
</Card>
<Card href="https://github.com/example/repo" variant="outlined">
<CardBody>
### 🐙 GitHub
View source code, report issues, and contribute to the project.
</CardBody>
</Card>
</CardGrid>Props API Documentation
Card Props
| Prop | Type | Default | Description | ||
|---|---|---|---|---|---|
variant | `'elevated' \ | 'outlined' \ | 'filled'` | 'elevated' | Visual style of the card |
children | ReactNode | required | Card content (use sub-components for structure) | ||
href | string | undefined | Makes the entire card a link | ||
onClick | function | undefined | Click handler for interactive cards | ||
as | ElementType | 'div' | HTML element to render as | ||
className | string | '' | Additional CSS classes |
CardImage Props
| Prop | Type | Default | Description |
|---|---|---|---|
src | string | required | Image source URL |
alt | string | required | Accessible image description |
aspectRatio | string | '16/9' | CSS aspect ratio for the image container |
className | string | '' | Additional CSS classes |
CardGrid Props
| Prop | Type | Default | Description |
|---|---|---|---|
columns | number | 3 | Number of columns at the largest breakpoint |
gap | number | 6 | Tailwind gap unit between cards |
children | ReactNode | required | Card components to arrange |
className | string | '' | Additional CSS classes |
Styling with Plain CSS
If you're not using Tailwind:
/* Card.module.css */
.card {
border-radius: 0.75rem;
overflow: hidden;
transition: all 0.2s ease;
}
.card-elevated {
background: white;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -2px rgba(0, 0, 0, 0.1);
border: 1px solid #f3f4f6;
}
.card-elevated:hover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
0 4px 6px -4px rgba(0, 0, 0, 0.1);
}
.card-outlined {
background: transparent;
border: 2px solid #e5e7eb;
}
.card-outlined:hover {
border-color: #60a5fa;
}
.card-filled {
background: #f9fafb;
border: 1px solid #e5e7eb;
}
.card-clickable {
cursor: pointer;
text-decoration: none;
color: inherit;
}
.card-clickable:hover {
transform: scale(1.02);
}
.card-clickable:active {
transform: scale(0.98);
}
.card-grid {
display: grid;
gap: 1.5rem;
grid-template-columns: 1fr;
}
@media (min-width: 768px) {
.card-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
.card-grid-3 { grid-template-columns: repeat(3, 1fr); }
.card-grid-4 { grid-template-columns: repeat(4, 1fr); }
}
.card-header {
padding: 1.5rem 1.5rem 0.5rem;
}
.card-body {
padding: 1rem 1.5rem;
}
.card-footer {
padding: 0.5rem 1.5rem 1.5rem;
border-top: 1px solid #f3f4f6;
}
.card-image {
width: 100%;
aspect-ratio: 16/9;
object-fit: cover;
}Responsive Card Patterns
Here's a pattern for feature cards that stack on mobile and sit side-by-side on desktop:
// Responsive card that stacks on mobile, side-by-side on desktop
export function FeatureCard({ icon, title, description, link }) {
return (
<Card variant="outlined" href={link}>
<CardBody>
<div className="flex flex-col sm:flex-row items-start gap-4">
<span className="text-3xl" aria-hidden="true">{icon}</span>
<div>
<h3 className="text-lg font-semibold mb-2">{title}</h3>
<p className="text-gray-600 dark:text-gray-400">{description}</p>
</div>
</div>
</CardBody>
</Card>
);
}Accessibility Notes
A few things to keep in mind:
- Semantic structure — Cards render as
<div>by default but switch to<a>when you passhref. The right element for the job.
- Image alt text —
CardImagerequires analtprop. Write something descriptive, or use an empty string for purely decorative images.
- Focus indicators — Interactive cards should have visible focus styles. Add
focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:outline-nonefor keyboard users.
- External links — When
hrefstarts withhttp, the component addstarget="_blank"andrel="noopener noreferrer"automatically.
- Content hierarchy — Use proper heading levels inside cards. If your cards live under an
<h2>, use<h3>for card titles.
- Color contrast — Make sure text in all card variants meets WCAG AA (4.5:1 for normal text, 3:1 for large text).
Advanced: Animated Card Hover
Add a subtle gradient overlay on hover:
export function AnimatedCard({ children, ...props }) {
return (
<Card
{...props}
className="group relative overflow-hidden"
>
{/* Gradient overlay on hover */}
<div className="absolute inset-0 bg-gradient-to-r from-blue-500/0 to-purple-500/0 group-hover:from-blue-500/5 group-hover:to-purple-500/5 transition-all duration-300" />
<div className="relative z-10">
{children}
</div>
</Card>
);
}Summary
This Card system uses the compound component pattern — Card, CardHeader, CardBody, CardFooter, CardImage all work together but give you full control over structure. Mix and match the pieces, throw them in a grid, make them clickable. One component system, tons of layouts.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Building a Card Component.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this MDX topic.
Search Terms
mdx, mdx tutorial, learn mdx, markdown, jsx, tutorial, components, card
Related MDX Topics