Card
A bordered surface with a hard shadow, composed from header, title, description, content, and footer parts.
stableCard.tsx
Examples
Composed card
Pro plan
popularFor teams shipping every day.
$19 / seat / month
card/basic.tsx
import { ArrowRight } from "lucide-react";
import { Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@streamuilib/react";
export default function CardBasic() {
return (
<Card className="w-full max-w-sm">
<CardHeader>
<div className="flex items-center justify-between gap-3">
<CardTitle>Pro plan</CardTitle>
<Badge tone="pink">popular</Badge>
</div>
<CardDescription>For teams shipping every day.</CardDescription>
</CardHeader>
<CardContent>
<p className="text-3xl font-bold">
$19<span className="text-sm font-normal text-ink-muted"> / seat / month</span>
</p>
</CardContent>
<CardFooter>
<Button className="w-full">
Start trial <ArrowRight aria-hidden />
</Button>
</CardFooter>
</Card>
);
}Tones
Soft tints keep large surfaces light.
paper
lime
pink
blue
violet
orange
card/tones.tsx
import { Card, CardContent, CardTitle, type CardTone } from "@streamuilib/react";
const tones: CardTone[] = ["paper", "lime", "pink", "blue", "violet", "orange"];
export default function CardTones() {
return (
<div className="grid w-full grid-cols-2 gap-4 sm:grid-cols-3">
{tones.map((tone) => (
<Card key={tone} tone={tone}>
<CardContent>
<CardTitle as="h4" className="font-mono text-sm">
{tone}
</CardTitle>
</CardContent>
</Card>
))}
</div>
);
}Installation
bun add @streamuilib/reactusage.tsx
import { Card, CardContent, CardHeader, CardTitle } from "@streamuilib/react";
<Card>
<CardHeader>
<CardTitle>Pro plan</CardTitle>
</CardHeader>
<CardContent>…</CardContent>
</Card>API
| Prop | Type | Default | Description |
|---|---|---|---|
| tone | "paper" | "lime" | "pink" | "blue" | "violet" | "orange" | "paper" | Surface tint. |
| ...props | ComponentProps<"div"> | — | Native div attributes. |
| Prop | Type | Default | Description |
|---|---|---|---|
| as | "h2" | "h3" | "h4" | "h3" | Heading level, to fit your page outline. |
| Prop | Type | Default | Description |
|---|---|---|---|
| ...props | native element props | — | Plain layout parts; className is merged last. |
Accessibility
- CardTitle is a real heading, so cards show up in a screen reader's heading list. Pick the level that fits your page.
- A card is a plain container. If the whole card should be clickable, put one link inside and stretch its hit area rather than wrapping everything in a link.
Source
packages/react/src/Card.tsx
import type { ComponentProps } from "react";
import { cn } from "./cn";
export type CardTone = "paper" | "lime" | "pink" | "blue" | "violet" | "orange";
const tones: Record<CardTone, string> = {
paper: "bg-paper-raised",
lime: "bg-lime-soft",
pink: "bg-pink-soft",
blue: "bg-blue-soft",
violet: "bg-violet-soft",
orange: "bg-orange-soft",
};
export type CardProps = ComponentProps<"div"> & {
/** Surface tint. Soft tints keep large areas light. */
tone?: CardTone;
};
/** A bordered surface with a hard shadow. Compose with the Card* parts. */
export function Card({ tone = "paper", className, ...props }: CardProps) {
return (
<div
className={cn("flex flex-col border-2 border-ink text-ink shadow-brutal", tones[tone], className)}
{...props}
/>
);
}
export function CardHeader({ className, ...props }: ComponentProps<"div">) {
return <div className={cn("flex flex-col gap-1.5 border-b-2 border-ink p-5", className)} {...props} />;
}
/** Renders an h3 by default; pass `as` to match your page's heading level. */
export function CardTitle({
as: Heading = "h3",
className,
...props
}: ComponentProps<"h3"> & { as?: "h2" | "h3" | "h4" }) {
return <Heading className={cn("text-lg leading-tight font-bold tracking-tight", className)} {...props} />;
}
export function CardDescription({ className, ...props }: ComponentProps<"p">) {
return <p className={cn("text-sm leading-relaxed text-ink-muted", className)} {...props} />;
}
export function CardContent({ className, ...props }: ComponentProps<"div">) {
return <div className={cn("flex-1 p-5", className)} {...props} />;
}
export function CardFooter({ className, ...props }: ComponentProps<"div">) {
return <div className={cn("flex flex-wrap items-center gap-3 border-t-2 border-ink p-5", className)} {...props} />;
}