Card
Surface component used for grouping content, actions, and metadata in PyColors UI.
Structured surfaces for product UILink to section
The Card component is a foundational surface used to group related content, actions, and metadata.
Use it for:
- dashboard tiles
- pricing blocks
- settings panels
- billing summaries
- feature cards
- list items
- empty states
- account sections
- product surfaces
Card is built on semantic tokens such as bg-card, border-border, and text-card-foreground, so it stays consistent across light and dark themes.
Core idea
Card creates structure. Use it to group meaningful content, not as decoration.
ImportLink to section
import { Card } from "@pycolors/ui";Basic usageLink to section
Use Card to group a title, description, content, and optional footer actions.
Account
Manage your profile settings.
Update personal details, security preferences, and integrations.
import {
Button,
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from "@pycolors/ui";
export function AccountCard() {
return (
<Card className="max-w-sm">
<CardHeader>
<CardTitle>Account</CardTitle>
<CardDescription>
Manage your profile settings.
</CardDescription>
</CardHeader>
<CardContent>
<div className="text-sm text-muted-foreground">
Update personal details, security preferences, and integrations.
</div>
</CardContent>
<CardFooter className="justify-end gap-2">
<Button variant="secondary">Cancel</Button>
<Button>Save</Button>
</CardFooter>
</Card>
);
}When to use CardLink to section
Use Card when content needs a clear surface, boundary, or grouping.
Dashboards
Settings
Billing
VariantsLink to section
Cards support semantic surface variants.
Use variants to adjust contrast without changing layout.
Default
Standard surface.
Muted
Subtle secondary surface.
Transparent
Layout-only surface.
import {
Card,
CardHeader,
CardTitle,
CardDescription,
} from "@pycolors/ui";
export function CardVariants() {
return (
<div className="grid gap-4 sm:grid-cols-3">
<Card>
<CardHeader>
<CardTitle>Default</CardTitle>
<CardDescription>Standard surface.</CardDescription>
</CardHeader>
</Card>
<Card variant="muted">
<CardHeader>
<CardTitle>Muted</CardTitle>
<CardDescription>Subtle secondary surface.</CardDescription>
</CardHeader>
</Card>
<Card variant="transparent" className="border-dashed">
<CardHeader>
<CardTitle>Transparent</CardTitle>
<CardDescription>Layout-only surface.</CardDescription>
</CardHeader>
</Card>
</div>
);
}Available variantsLink to section
| Variant | Purpose |
|---|---|
default | Main surface using bg-card |
muted | Secondary surface using a softer background |
transparent | Layout-only container with no filled background |
Variant rule
Use default for primary surfaces, muted for secondary groups, and transparent when you only need structure.
Interactive cardsLink to section
interactive adds visual affordances only — cursor, hover background, and a focus-visible ring. Card never attaches its own click or keyboard handling, so an interactive card must compose asChild with a real <button> for an action or a real <a>/Link for navigation. Those elements provide correct keyboard, focus, and click semantics natively — Card does not need to (and must not) recreate them.
import {
Card,
CardHeader,
CardTitle,
CardDescription,
} from "@pycolors/ui";
export function InteractiveCards() {
return (
<div className="grid gap-4 sm:grid-cols-2">
<Card asChild interactive>
<button
type="button"
className="block w-full text-left"
onClick={() => selectPlan("pro")}
>
<CardHeader>
<CardTitle>Select a plan</CardTitle>
<CardDescription>
A real button gives native click and keyboard behavior for free.
</CardDescription>
</CardHeader>
</button>
</Card>
<Card asChild interactive variant="muted">
<a href="/pricing" className="block">
<CardHeader>
<CardTitle>View pricing</CardTitle>
<CardDescription>
A real link gives native navigation and open-in-new-tab behavior.
</CardDescription>
</CardHeader>
</a>
</Card>
</div>
);
}Keyboard support
interactive never adds role, tabIndex, or keyboard handling — it is visual only. A bare Card interactive with no asChild target is not keyboard or screen-reader accessible. Always compose asChild with a real button for actions or a real a/Link for navigation.
With iconLink to section
Use asChild to render Card as another element while preserving Card styling.
This is useful for link cards.
import {
Card,
CardHeader,
CardTitle,
CardDescription,
} from "@pycolors/ui";
export function CardAsLink() {
return (
<Card asChild interactive className="max-w-sm">
<a href="/docs" className="block">
<CardHeader>
<CardTitle>Read the docs</CardTitle>
<CardDescription>Go to documentation →</CardDescription>
</CardHeader>
</a>
</Card>
);
}CompositionLink to section
A Card usually follows this structure:
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
<CardDescription>Description</CardDescription>
</CardHeader>
<CardContent>
Content
</CardContent>
<CardFooter>
Actions
</CardFooter>
</Card>Use each slot intentionally:
| Slot | Purpose |
|---|---|
CardHeader | Introduces the surface |
CardTitle | Names the grouped content |
CardDescription | Adds short context |
CardContent | Holds the main body |
CardFooter | Holds actions or supporting metadata |
Usage patternsLink to section
Start with the content group
Use Card only when the content belongs together.
Add a clear title
Most cards should have a title that explains the purpose of the surface.
Keep actions in the footer
Footer actions make the card easier to scan and keep layout predictable.
Use interactivity deliberately
Interactive cards should be clickable or selectable. Static cards should not have hover affordances.
Preserve semantic behavior
Use asChild with a real link for navigational cards.
Card vs section vs list itemLink to section
| Situation | Use |
|---|---|
| Grouped content with a visible surface | Card |
| Large page section with headings | Section |
| Repeated compact rows | List item |
| Navigation tile | Card with asChild link |
| KPI or metric | Card |
| Table data | Table |
| Temporary status or error | Alert or EmptyState |
Decision rule
Use Card when the surface helps users understand grouping, priority, or interaction.
APILink to section
Components
| Component | Description |
|---|---|
Card | Root surface |
CardHeader | Header area |
CardTitle | Card heading |
CardDescription | Supporting text |
CardContent | Main content area |
CardFooter | Footer actions or metadata |
Card props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | CardVariant | "default" | Surface style |
interactive | boolean | false | Adds hover and focus-visible feedback |
asChild | boolean | false | Render via Radix Slot |
className | string | — | Additional Tailwind classes |
Card extends standard HTML div props.
React.HTMLAttributes<HTMLDivElement>TypeScript typesLink to section
export type CardVariant =
| "default"
| "muted"
| "transparent";
export type CardInteractive = boolean;AccessibilityLink to section
Guidelines:
- use meaningful headings inside cards when they introduce a section
interactiveonly adds visual affordances (cursor, hover, focus-visible ring) — it never addsrole,tabIndex, or keyboard handling- a bare
Card interactivewith noasChildtarget is not keyboard or screen-reader accessible — it is styling only - use
asChildwith a reala/Linkfor navigation cards - use
asChildwith a realbuttonfor action cards asChild interactivewrapping a non-focusable element (for example a plaindiv) is invalid — the slotted child must be a real interactive element- avoid nested interactive controls inside a clickable card
- keep focus states visible for interactive cards
- do not make a card interactive only for visual decoration
Accessibility rule
Card never synthesizes keyboard or focus behavior. An interactive card is only truly accessible when asChild wraps a real a/Link (navigation) or button (action) — those elements provide correct keyboard, focus, and click semantics natively.
Prefer / avoidLink to section
Prefer
- clear grouping
- consistent card rhythm
- semantic headings
- footer actions for card-level actions
- real link semantics for navigation cards
Avoid
- cards used only for decoration
- too many nested cards
- interactive styling on static content
- clickable cards without link or button semantics
- multiple competing actions inside one clickable card
Product copy guidelinesLink to section
Card copy should make the grouped content easy to understand.
Strong title examples
Titles should describe the surface immediately without extra wording.