Card
A flexible container with four visual variants and an optional interactive mode. Composed from CardHeader, CardBody, and CardFooter for structured layouts.
Preview
Standard bordered card with surface background. The workhorse variant.
Drop shadow communicates that this card floats above the page surface.
Variants
Four variants for different elevations and semantic contexts.
Border + surface background
Drop shadow, no extra border style
No border, subtle filled background
Green-tinted border and background
Interactive
Adding interactive enables hover elevation, accent border on hover, and a subtle press scale. Pair with as="button" or as="a" for correct semantics.
Hover me
Hover me
Hover me
Implementation
Card, CardHeader, CardBody, and CardFooter are all named exports from the same file. Use them together for structured layouts or use Card alone for simple containers.
import { Card, CardHeader, CardBody, CardFooter } from "@/components/ui/Card";
import { Button } from "@/components/ui/Button";
// Default — border + surface background
<Card>
<CardHeader>
<h3 className="text-[14px] font-semibold">Project Alpha</h3>
</CardHeader>
<CardBody>
<p className="text-[13px] text-[rgb(var(--text-secondary))]">
A brief description of the project and its current status.
</p>
</CardBody>
<CardFooter>
<Button size="sm" variant="secondary">Open</Button>
</CardFooter>
</Card>
// Elevated — drop shadow
<Card variant="elevated">
<CardBody>Elevated card with depth shadow.</CardBody>
</Card>
// Ghost — subtle filled background, no border
<Card variant="ghost">
<CardBody>Ghost card blends into the background.</CardBody>
</Card>
// Accent — green-tinted border and background
<Card variant="accent">
<CardBody>Accent card for highlighted content.</CardBody>
</Card>
// Interactive — hover + press states
<Card interactive as="button" onClick={() => {}}>
<CardBody>Click me</CardBody>
</Card>Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "elevated" | "ghost" | "accent" | "default" | Controls border, background, and shadow treatment. |
interactive | boolean | false | Adds hover elevation, accent border on hover, and active scale. |
as | "div" | "button" | "a" | "div" | Render the card as a different HTML element for semantic correctness. |
Mobile
Cards on mobile should fill the available width and be large enough to tap comfortably. Avoid dense multi-column grids on narrow screens.
Browse
Design Principles
Core concepts behind Sitka's approach
Button
Interactive control for actions
Glass Surface
Layered blur and opacity system
| Scenario | Guidance |
|---|---|
| Grid layout | Use a single column on screens below 640px. Two columns can work above 480px if cards don't contain much text. grid-cols-1 sm:grid-cols-2 is the safe default. |
| Touch target | Interactive cards should be at least 44px tall. Content-heavy cards usually exceed this naturally, but icon cards and small thumbnails may need extra padding. |
| Swipe in lists | Horizontal card carousels should use scroll-snap-type: x mandatory with scroll-snap-align: start on each card so swipes land cleanly. |
| Hover states | Cards with hover effects (shadow lift, scale) should still look correct without hover on touch. Add an active: pressed state to replace hover feedback. |
| Image aspect ratio | Use aspect-video or aspect-square on card images to prevent layout shift as images load. Avoid auto height with no explicit ratio. |
Accessibility
- →Use as="button" or as="a" for interactive cards — never attach onClick to a <div>.
- →Interactive cards have active:scale feedback; avoid additional animations inside that compound the motion.
- →Ensure card content contains a meaningful heading or label for screen readers.
- →Focus ring is inherited from the element — <button> cards receive it automatically.