Card
freeCard creates a bounded surface for related content, summaries, and nearby actions.
Preview
Dark
Every component matched spec on the first pass, and the whole project shipped two weeks ahead of schedule.
Marcus Webb
Design Lead, Northwind
5.0
import { PiQuotes, PiStar } from 'react-icons/pi'
import Avatar from '@/components/ui/Avatar';
import Card from '@/components/ui/Card';
export default function UsageDemo() {
return (
<div className="w-80 max-w-full">
<Card>
<div className="space-y-4">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-muted">
<PiQuotes className="h-5 w-5 text-foreground" />
</div>
<p className="text-foreground">
Every component matched spec on the first pass, and the whole
project shipped two weeks ahead of schedule.
</p>
<div className="flex items-center justify-between gap-4 mt-12">
<div className="flex items-center gap-2">
<Avatar
size="sm"
src="/img/avatars/thumb-9.jpg"
alt="Marcus Webb"
/>
<div className="min-w-0">
<div className="font-medium text-foreground">
Marcus Webb
</div>
<div className="text-xs text-muted-foreground">
Design Lead, Northwind
</div>
</div>
</div>
<div className="flex items-center gap-1 text-warning">
<PiStar className="h-4 w-4" fill="currentColor" />
<span className="font-medium text-foreground">5.0</span>
</div>
</div>
</div>
</Card>
</div>
);
}Installation
Add this component with the NateUI CLI.
npx nateui@latest add CardExamples
Basic
Preview
Dark
Customer profile
Keep normal card content on the default body padding and let the shared surface provide the border, radius, and background.
import Card from '@/components/ui/Card';
export default function BasicDemo() {
return (
<div className="w-80 max-w-full">
<Card>
<div className="space-y-2">
<div className="font-semibold text-foreground">Customer profile</div>
<p className="text-muted-foreground">
Keep normal card content on the default body padding and let the
shared surface provide the border, radius, and background.
</p>
</div>
</Card>
</div>
);
}Header And Footer
Preview
Dark
Team roadmap
Outlines the next three releases, who is driving each one, and where the open risks are.
import { PiDotsThree } from 'react-icons/pi'
import Avatar from '@/components/ui/Avatar';
import Button from '@/components/ui/Button';
import Card from '@/components/ui/Card';
export default function HeaderFooterDemo() {
return (
<div className="w-96 max-w-full">
<Card
header={{
bordered: false,
content: (
<span className="text-lg font-medium text-foreground">
Team roadmap
</span>
),
extra: (
<Button
size="sm"
variant="ghost"
icon={<PiDotsThree />}
aria-label="More options"
/>
),
}}
footer={{
content: (
<div className="flex items-center justify-between gap-4">
<div className="flex items-center gap-2">
<Avatar
size="sm"
src="/img/avatars/thumb-14.jpg"
alt="Priya Anand"
/>
<span className="font-medium text-foreground">
Priya Anand
</span>
</div>
<span className="text-muted-foreground">4h ago</span>
</div>
),
}}
>
<p className="text-muted-foreground">
Outlines the next three releases, who is driving each one, and
where the open risks are.
</p>
</Card>
</div>
);
}Divided Body
Preview
Dark
https://linear.app/acme/issue/pay-214
Homepage redesign - final.png
Sprint retro notes
2 linked tasks
Vendor contract.pdf
4 linked tasks
import {
PiArrowsOut,
PiDotsThreeVertical,
PiDownloadSimple,
PiImage,
PiLink,
PiLinkSimple,
PiPaperclip,
PiPencilSimpleLine,
} from 'react-icons/pi'
import Button from '@/components/ui/Button';
import Card from '@/components/ui/Card';
import Tag from '@/components/ui/Tag';
const files = [
{
icon: PiLink,
label: 'https://linear.app/acme/issue/pay-214',
action: 'expand',
},
{
icon: PiImage,
label: 'Homepage redesign - final.png',
action: 'expand',
},
{
icon: PiPencilSimpleLine,
label: 'Sprint retro notes',
tasks: 2,
action: 'download',
},
{
icon: PiPaperclip,
label: 'Vendor contract.pdf',
tasks: 4,
action: 'download',
},
];
export default function DividedBodyDemo() {
return (
<div className="w-96 max-w-full">
<Card bodyClass="p-0">
<div className="divide-y">
{files.map((file) => {
const RowIcon = file.icon;
const ActionIcon = file.action === 'expand' ? PiArrowsOut : PiDownloadSimple;
return (
<div
key={file.label}
className="flex items-center justify-between gap-4 p-4"
>
<div className="flex min-w-0 items-center gap-2">
<RowIcon className="h-4 w-4 shrink-0 text-muted-foreground" />
<span className="truncate text-foreground">
{file.label}
</span>
</div>
<div className="flex shrink-0 items-center gap-2">
{file.tasks && (
<Tag prefix={<PiLinkSimple className="mr-1 h-3.5 w-3.5" />}>
{file.tasks} linked tasks
</Tag>
)}
<Button
variant="ghost"
size="sm"
icon={<ActionIcon />}
aria-label={
file.action === 'expand' ? 'Expand' : 'Download'
}
/>
<Button
variant="ghost"
size="sm"
icon={<PiDotsThreeVertical />}
aria-label="More options"
/>
</div>
</div>
);
})}
</div>
</Card>
</div>
);
}Borderless
Preview
Dark
Two Days in Kyoto
Quiet ryokans, short train rides, and temples that open before the crowds.
import { PiMapPin } from 'react-icons/pi'
import Card from '@/components/ui/Card';
import Tag from '@/components/ui/Tag';
export default function BorderlessDemo() {
return (
<div className="w-96 max-w-full">
<Card bordered={false} bodyClass="p-0" className="overflow-hidden">
<div className="relative aspect-4/5 w-full">
<img
src="/img/thumbs/misc/img-6.png"
alt=""
className="absolute inset-0 h-full w-full object-cover"
/>
<Tag
prefix={<PiMapPin className="mr-1 h-3.5 w-3.5" />}
className="absolute left-4 top-4 border-transparent bg-background/90 text-foreground backdrop-blur-sm"
>
Featured Stay
</Tag>
<div className="absolute inset-x-0 bottom-0 bg-linear-to-t from-black/85 via-black/40 to-transparent p-4 pt-16">
<div className="text-lg font-semibold text-white">
Two Days in Kyoto
</div>
<p className="mt-1 text-white/80">
Quiet ryokans, short train rides, and temples that open before
the crowds.
</p>
</div>
</div>
</Card>
</div>
);
}Clickable
Preview
Dark
Integrations
Connect the tools your team already uses without leaving the dashboard.
import Card from '@/components/ui/Card';
import { ChevronRight } from '@/components/ui/Icons';
export default function ClickableDemo() {
return (
<div className="w-full max-w-112.5">
<Card clickable bodyClass="p-0" className="transition-transform hover:scale-[1.02] hover:bg-muted/30">
<div className="flex items-center gap-4 p-4">
<div className="flex h-28 w-28 shrink-0 items-center justify-center rounded-2xl bg-muted border p-2">
<img
src="/img/thumbs/misc/img-2.png"
alt=""
className="h-full w-full rounded-lg object-cover"
/>
</div>
<div className="min-w-0 flex-1">
<div className="font-semibold text-foreground text-base">Integrations</div>
<p className="mt-1 text-sm text-muted-foreground">
Connect the tools your team already uses without leaving the
dashboard.
</p>
</div>
<ChevronRight className="shrink-0 text-xl" />
</div>
</Card>
</div>
);
}Media
Preview
Dark
Layout patterns that cut checkout
A walkthrough of the spacing, copy, and validation choices that move the needle on multi-step forms.
import { ChevronRight } from '@/components/ui/Icons';
import Button from '@/components/ui/Button';
import Card from '@/components/ui/Card';
export default function MediaDemo() {
return (
<div className="w-80 max-w-full">
<Card bodyClass="p-0" className="overflow-hidden">
<img
src="/img/thumbs/misc/img-1.png"
alt=""
className="aspect-video w-full object-cover"
/>
<div className="space-y-8 p-4">
<div className="space-y-4">
<div className="text-base font-semibold text-foreground">
Layout patterns that cut checkout
</div>
<p className="text-muted-foreground">
A walkthrough of the spacing, copy, and validation choices
that move the needle on multi-step forms.
</p>
</div>
<Button
block
variant="solid"
icon={<ChevronRight />}
iconAlignment="end"
>
Learn More
</Button>
</div>
</Card>
</div>
);
}API
Card accepts the props below plus native props for the root div.
| Prop | Description | Type | Default |
|---|---|---|---|
bodyClass | Class names applied to the card body section. | string | - |
bordered | Uses the default bordered card surface. Pass false for the shadow card treatment. | boolean | true |
children | Main card body content. | ReactNode | - |
className | Class names applied to the card root. | string | - |
clickable | Adds pointer cursor and disables text selection on the card root. | boolean | false |
footer | Optional footer section configuration. | CardFooterConfig | {} |
header | Optional header section configuration. | CardHeaderConfig | {} |
onClick | Called when the card root is clicked. | CardClickHandler | - |
ref | Ref forwarded to the card root. | Ref<HTMLDivElement> | - |
...nativeDivProps | Native props for the root div. | NativeCardDivProps | - |
Types
type CardHeaderConfig = {
content?: string | ReactNode;
className?: string;
bordered?: boolean;
extra?: string | ReactNode;
};
type CardFooterConfig = {
content?: string | ReactNode;
className?: string;
bordered?: boolean;
};
type CardClickHandler = (event: MouseEvent<HTMLDivElement>) => void;
type NativeCardDivProps = ComponentPropsWithRef<'div'>;