Card
A content block composed of Card.Header, Card.Body and Card.Footer that can also act as a link.
Buyurtma #1042
Bugun, 14:20
'use client';
import { Avatar, Badge, Button, Card } from '@akhatmirzo/ui';
export default function CardBasic() {
return (
<Card className="w-full max-w-md">
<Card.Header
title="Buyurtma #1042"
description="Bugun, 14:20"
action={
<Badge color="primary" dot>
Yangi
</Badge>
}
/>
<Card.Body>
<div className="flex items-center gap-3">
<Avatar name="Sarvar Abduxoliqov" size="sm" />
<div className="flex flex-col">
<span className="font-medium">Sarvar Abduxoliqov</span>
<span className="text-text-muted">3 ta mahsulot · 245 000 so'm</span>
</div>
</div>
</Card.Body>
<Card.Footer className="justify-end">
<Button variant="ghost">Bekor qilish</Button>
<Button variant="primary">Tasdiqlash</Button>
</Card.Footer>
</Card>
);
}
Import
import { Card } from '@akhatmirzo/ui';When to use
- To group related information — an order, a product, a stat, a settings section.
- Compose it:
Card.Header(title, description, an action on the right),Card.BodyandCard.Footer. All of them are optional. - If the whole card is clickable, pass an
<a>or<button>withinteractiveandasChild— not a<div onClick>. - Don't nest cards. A
Divideror some spacing is enough for inner grouping.
Variants
elevated (default) has a shadow and border and stands out on a white page. outline is just a
border, good for dense lists. soft has no border and a surface-muted background.
Elevated
Soya va chegara (standart)
Outline
Faqat chegara
Soft
Och kulrang fon
'use client';
import { Card } from '@akhatmirzo/ui';
export default function CardVariants() {
return (
<div className="grid w-full grid-cols-1 gap-4 sm:grid-cols-3">
<Card variant="elevated" padding="sm">
<Card.Header title="Elevated" description="Soya va chegara (standart)" />
</Card>
<Card variant="outline" padding="sm">
<Card.Header title="Outline" description="Faqat chegara" />
</Card>
<Card variant="soft" padding="sm">
<Card.Header title="Soft" description="Och kulrang fon" />
</Card>
</div>
);
}
Padding
padding: none is 0, sm 16px, md (default) 24px and lg 32px. The gap between sections
scales with it.
'use client';
import { Card } from '@akhatmirzo/ui';
const paddings = [
{ padding: 'sm', px: 16 },
{ padding: 'md', px: 24 },
{ padding: 'lg', px: 32 },
] as const;
export default function CardPadding() {
return (
<div className="grid w-full grid-cols-1 gap-4 sm:grid-cols-3">
{paddings.map(({ padding, px }) => (
<Card key={padding} variant="outline" padding={padding}>
<div className="rounded-md bg-primary-soft p-2 text-xs font-medium text-primary-soft-foreground">
{padding} · {px}px
</div>
</Card>
))}
</div>
);
}
With media
With padding="none" and overflow-hidden, an image runs to the card's edges and you add
padding around the text yourself.
Samarqand bo'ylab sayohat
2 kun · 4 ta joy
'use client';
import { Badge, Card } from '@akhatmirzo/ui';
export default function CardMedia() {
return (
<Card padding="none" className="w-full max-w-sm overflow-hidden">
<div className="h-32 bg-linear-to-br from-primary to-info" />
<div className="flex flex-col gap-3 p-6">
<Card.Header title="Samarqand bo'ylab sayohat" description="2 kun · 4 ta joy" />
<Card.Footer>
<Badge color="success" size="sm">
Joy bor
</Badge>
<Badge size="sm">Guruh</Badge>
</Card.Footer>
</div>
</Card>
);
}
Clickable card
interactive raises the shadow on hover and shows a pointer cursor. It's styling only — for
keyboard support, pass an <a> or <button> with asChild, so the card gets Tab focus and
opens with Enter.
'use client';
import { Card } from '@akhatmirzo/ui';
const reports = [
{ title: 'Sotuvlar', description: "Oktyabr · 48 250 000 so'm" },
{ title: 'Mijozlar', description: '1 204 ta faol mijoz' },
];
export default function CardInteractive() {
return (
<div className="grid w-full grid-cols-1 gap-4 sm:grid-cols-2">
{reports.map((report) => (
<Card key={report.title} variant="outline" interactive asChild>
<a href="#props">
<Card.Header title={report.title} description={report.description} />
</a>
</Card>
))}
</div>
);
}
import Link from 'next/link';
<Card interactive asChild>
<Link href="/reports/sales">
<Card.Header title="Sales" description="October" />
</Link>
</Card>;Props
Card
Card accepts every other <div> attribute.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'elevated' | 'outline' | 'soft' | 'elevated' | Look |
padding | 'none' | 'sm' | 'md' | 'lg' | 'md' | Padding: 0 / 16 / 24 / 32px |
interactive | boolean | null | false | Hover and focus styles (styling only) |
asChild | boolean | false | Renders its child instead of its own element (e.g. <a>) |
Card.Header
Also exported as CardHeader. Accepts the remaining <div> attributes; children render below
the title and description.
| Prop | Type | Default | Description |
|---|---|---|---|
title | ReactNode | — | Title (<h3>) |
description | ReactNode | — | Muted text under the title |
action | ReactNode | — | Element on the right: a badge, button or menu |
Card.Body and Card.Footer
CardBody and CardFooter are plain <div>s that accept all their attributes. Body sets the
text to text-sm; Footer lays its children out in a row with gap-2 (use
className="justify-end" to push them right).
Data attributes
On the Card root: data-variant, data-padding and data-interactive. cardVariants is also
exported if you need the styles on another element.
Accessibility
- A plain
<div>with no role. If it's a meaningful section, pass a<section>or<article>withasChild. - The
Card.Headertitle is an<h3>. If that doesn't fit your page's heading order, put your own heading inchildreninstead oftitle. - A clickable card only works from the keyboard when it's a real
<a>/<button>viaasChild; the focus ring then wraps the whole card.