Card
Flexible surface container for grouping related content with optional header, body, footer, and media slots.
Rendered as a <div> by default; interactive mode adds tabIndex=0 for keyboard focus. Use asChild with an <a> or <button> for native semantics when the whole card is actionable.
Preview
tsx
import { Card, CardBody, CardDescription, CardTitle } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<Card style={{ maxWidth: '24rem' }}>
<CardBody>
<CardTitle>Getting started</CardTitle>
<CardDescription>
A basic card with a title and description inside the body.
</CardDescription>
</CardBody>
</Card>
);
}
With header and footer
Section titled “With header and footer”Use CardHeader, CardBody, and CardFooter for structured three-zone layouts.
Preview
tsx
import {
Button,
Card,
CardBody,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<Card style={{ maxWidth: '24rem' }}>
<CardHeader>
<CardTitle>Project overview</CardTitle>
<CardDescription>Last updated 2 hours ago</CardDescription>
</CardHeader>
<CardBody>
<p style={{ margin: 0, fontSize: '0.875rem' }}>
This card uses separate header, body, and footer sections for a structured layout.
</p>
</CardBody>
<CardFooter style={{ display: 'flex', gap: '0.5rem', justifyContent: 'flex-end' }}>
<Button variant="ghost" size="sm">
Cancel
</Button>
<Button variant="solid" size="sm">
Save
</Button>
</CardFooter>
</Card>
);
}
Interactive
Section titled “Interactive”Pass interactive to add hover/focus styles and tabIndex=0. Use asChild to render the card as a native <a> or <button> for full semantics.
Preview
tsx
import { Card, CardBody, CardDescription, CardTitle } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<div style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap' }}>
<Card
interactive
style={{ maxWidth: '18rem', cursor: 'pointer' }}
onClick={() => alert('Card clicked')}
>
<CardBody>
<CardTitle>Interactive card</CardTitle>
<CardDescription>
This card is focusable and responds to click, hover, and keyboard events.
</CardDescription>
</CardBody>
</Card>
<Card interactive asChild style={{ maxWidth: '18rem' }}>
<a href="/components/card">
<CardBody>
<CardTitle>Link card</CardTitle>
<CardDescription>Uses asChild to render the card as an anchor element.</CardDescription>
</CardBody>
</a>
</Card>
</div>
);
}
Use CardMedia to wrap arbitrary media (images, video, or coloured placeholders) with consistent aspect-ratio sizing.
Preview
tsx
import { Card, CardBody, CardDescription, CardMedia, CardTitle } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<Card style={{ maxWidth: '24rem', overflow: 'hidden' }}>
<CardMedia
aspectRatio="16/9"
style={{
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<rect x="3" y="3" width="18" height="18" rx="2" stroke="white" strokeWidth="1.5" />
<circle cx="8.5" cy="8.5" r="1.5" fill="white" />
<path
d="M21 15l-5-5L5 21"
stroke="white"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</CardMedia>
<CardBody>
<CardTitle>Media card</CardTitle>
<CardDescription>
Use CardMedia to wrap any arbitrary media content — images, video, or coloured
placeholders.
</CardDescription>
</CardBody>
</Card>
);
}
PropTypeDefaultDescription
variant
"outlined"|"elevated"|"filled"|"ghost"
outlined
Visual treatment. `outlined` uses a border, `elevated` adds a shadow,
`filled` paints a subtle surface tint, `ghost` is borderless.
size
"sm"|"md"|"lg"
md
Internal padding scale applied to the card and its standard parts.
orientation
"vertical"|"horizontal"
vertical
Lays children left-to-right (e.g. image beside body) instead of top-to-bottom.
interactive
boolean
false
Adds hover/focus affordances and a `tabIndex={0}` so the whole card is
keyboard-focusable. Combine with an `onClick` or wrap in a link.
asChild
boolean
false
Render the props onto the immediate child via Slot composition instead of
a wrapping `div`. Useful for turning the card into an `<a>` or `<button>`.
Accessibility
Section titled “Accessibility”- Rendered as a
<div>by default — purely presentational. interactiveaddstabIndex=0and focus ring styles for keyboard navigation, but the element still has no implicit role. For actionable cards, preferasChildwith an<a>(link cards) or wrap contents in a<button>.- Heading hierarchy inside
CardTitledefaults to<h3>— override with theasprop to match the page’s document outline.
Recipes
Section titled “Recipes”- Use
variant="elevated"for cards that float above the page surface. - Use
orientation="horizontal"withCardImage horizontalfor side-by-side image+content layouts. - Compose with
Badgein the header for status indicators. - Nest
AlertinsideCardBodyto show inline validation feedback within a card form.