ZaidanHomeDocsComponentsBlocksChartsTypesetCreate

Command Palette

Search for a command to run...

GitHub
New
Sections
  • Introduction
  • Components
  • Blocks
  • Installation
  • Customization
  • Dark Mode
  • Typeset
  • Zaidan Skills
  • FAQ
  • Roadmap
  • Changelog
Installation
  • Astro
  • Manual
  • Solid Start
  • TanStack Router
  • TanStack Start
  • Vite
Blocks
  • Data Grid
  • Event Calendar
  • Filters
  • Gantt
  • Image Crop
  • Kanban
  • Message Scroller
  • Questionnaire
  • Sortable
Components
  • Accordion
  • Alert
  • Alert Dialog
  • Aspect Ratio
  • Attachment
  • Avatar
  • Badge
  • Breadcrumb
  • Bubble
  • Button
  • Button Group
  • Calendar
  • Card
  • Carousel
  • Chart
  • Checkbox
  • Collapsible
  • Combobox
  • Command
  • Context Menu
  • Dialog
  • Drawer
  • Dropdown Menu
  • Empty
  • Field
  • Hover Card
  • Input
  • Input Group
  • Input OTP
  • Item
  • Kbd
  • Label
  • Marker
  • Menubar
  • Message
  • Native Select
  • Navigation Menu
  • Pagination
  • Popover
  • Progress
  • Radio Group
  • Resizable
  • Scroll Area
  • Select
  • Separator
  • Sheet
  • Sidebar
  • Skeleton
  • Slider
  • Spinner
  • Switch
  • Table
  • Tabs
  • Textarea
  • Toast
  • Toggle
  • Toggle Group
  • Tooltip

Card

Displays a card with header, content, and footer.

Login to your account
Enter your email below to login to your account
Forgot your password?
1
import { Button } from "~/components/ui/button";
2
import {
3
Card,
4
CardAction,
5
CardContent,
6
CardDescription,
7
CardFooter,
8
CardHeader,
9
CardTitle,
10
} from "~/components/ui/card";
11
import { Input } from "~/components/ui/input";
12
import { Label } from "~/components/ui/label";
13
14
export default function CardDemo() {
15
return (
16
<Card class="w-full max-w-sm">
17
<CardHeader>
18
<CardTitle>Login to your account</CardTitle>
19
<CardDescription>Enter your email below to login to your account</CardDescription>
20
<CardAction>
21
<Button variant="link">Sign Up</Button>
22
</CardAction>
23
</CardHeader>
24
<CardContent>
25
<form>
26
<div class="flex flex-col gap-6">
27
<div class="grid gap-2">
28
<Label for="card-demo-email">Email</Label>
29
<Input id="card-demo-email" type="email" placeholder="m@example.com" required />
30
</div>
31
<div class="grid gap-2">
32
<div class="flex items-center">
33
<Label for="card-demo-password">Password</Label>
34
<a
35
href="/docs"
36
class="ml-auto inline-block text-sm underline-offset-4 hover:underline"
37
>
38
Forgot your password?
39
</a>
40
</div>
41
<Input id="card-demo-password" type="password" required />
42
</div>
43
</div>
44
</form>
45
</CardContent>
46
<CardFooter class="flex-col gap-2">
47
<Button type="submit" class="w-full">
48
Login
49
</Button>
50
<Button variant="outline" class="w-full">
51
Login with Google
52
</Button>
53
</CardFooter>
54
</Card>
55
);
56
}

Installation

pnpm dlx shadcn@latest add @zaidan/card
npx shadcn@latest add @zaidan/card
yarn dlx shadcn@latest add @zaidan/card
bunx --bun shadcn@latest add @zaidan/card

Usage

1
import {
2
Card,
3
CardAction,
4
CardContent,
5
CardDescription,
6
CardFooter,
7
CardHeader,
8
CardTitle,
9
} from "~/components/ui/card";
1
<Card>
2
<CardHeader>
3
<CardTitle>Card Title</CardTitle>
4
<CardDescription>Card Description</CardDescription>
5
<CardAction>Card Action</CardAction>
6
</CardHeader>
7
<CardContent>
8
<p>Card Content</p>
9
</CardContent>
10
<CardFooter>
11
<p>Card Footer</p>
12
</CardFooter>
13
</Card>

Composition

Use the following composition to build a Card:

Card
├── CardHeader
│ ├── CardTitle
│ ├── CardDescription
│ └── CardAction
├── CardContent
└── CardFooter

Size

Use the size="sm" prop to set the card to its compact size.

Scheduled reports
Weekly snapshots. No more manual exports.
  • Choose a schedule (daily, or weekly).
  • Send to channels or specific teammates.
  • Include charts, tables, and key metrics.
1
import { ChevronRight } from "lucide-solid";
2
import { Button } from "~/components/ui/button";
3
import {
4
Card,
5
CardContent,
6
CardDescription,
7
CardFooter,
8
CardHeader,
9
CardTitle,
10
} from "~/components/ui/card";
11
12
export default function CardSmall() {
13
const featureName = "Scheduled reports";
14
15
return (
16
<Card size="sm" class="mx-auto w-full max-w-xs">
17
<CardHeader>
18
<CardTitle>{featureName}</CardTitle>
19
<CardDescription>Weekly snapshots. No more manual exports.</CardDescription>
20
</CardHeader>
21
<CardContent>
22
<ul class="grid gap-2 py-2 text-sm">
23
<li class="flex gap-2">
24
<ChevronRight class="mt-0.5 size-4 shrink-0 text-muted-foreground" />
25
<span>Choose a schedule (daily, or weekly).</span>
26
</li>
27
<li class="flex gap-2">
28
<ChevronRight class="mt-0.5 size-4 shrink-0 text-muted-foreground" />
29
<span>Send to channels or specific teammates.</span>
30
</li>
31
<li class="flex gap-2">
32
<ChevronRight class="mt-0.5 size-4 shrink-0 text-muted-foreground" />
33
<span>Include charts, tables, and key metrics.</span>
34
</li>
35
</ul>
36
</CardContent>
37
<CardFooter class="flex-col gap-2">
38
<Button size="sm" class="w-full">
39
Set up scheduled reports
40
</Button>
41
<Button variant="outline" size="sm" class="w-full">
42
See what&apos;s new
43
</Button>
44
</CardFooter>
45
</Card>
46
);
47
}

Spacing

Use the --card-spacing CSS variable to control the gap between sections and the inset of card parts.

Login to your account
Enter your email below to login to your account
Forgot your password?
1
import { createMemo, createSignal, For } from "solid-js";
2
import { Button } from "~/components/ui/button";
3
import {
4
Card,
5
CardAction,
6
CardContent,
7
CardDescription,
8
CardFooter,
9
CardHeader,
10
CardTitle,
11
} from "~/components/ui/card";
12
import { Input } from "~/components/ui/input";
13
import { Label } from "~/components/ui/label";
14
import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";
15
16
const spacingOptions = [
17
{
18
class: "[--card-spacing:--spacing(4)]",
19
label: "16px",
20
value: "4",
21
},
22
{
23
class: "[--card-spacing:--spacing(5)]",
24
label: "20px",
25
value: "5",
26
},
27
{
28
class: "[--card-spacing:--spacing(6)]",
29
label: "24px",
30
value: "6",
31
},
32
{
33
class: "[--card-spacing:--spacing(8)]",
34
label: "32px",
35
value: "8",
36
},
37
];
38
39
export default function CardSpacing() {
40
const [spacing, setSpacing] = createSignal("4");
41
const selectedSpacing = createMemo(() =>
42
spacingOptions.find((option) => option.value === spacing()),
43
);
44
45
return (
46
<div class="mx-auto grid w-full max-w-sm gap-4">
47
<ToggleGroup
48
value={spacing()}
49
onChange={(value) => setSpacing(value ?? "4")}
50
variant="outline"
51
size="sm"
52
class="justify-center"
53
>
54
<For each={spacingOptions}>
55
{(option) => <ToggleGroupItem value={option.value}>{option.label}</ToggleGroupItem>}
56
</For>
57
</ToggleGroup>
58
<Card class={selectedSpacing()?.class}>
59
<CardHeader>
60
<CardTitle>Login to your account</CardTitle>
61
<CardDescription>Enter your email below to login to your account</CardDescription>
62
<CardAction>
63
<Button variant="link">Sign Up</Button>
64
</CardAction>
65
</CardHeader>
66
<CardContent>
67
<form>
68
<div class="flex flex-col gap-6">
69
<div class="grid gap-2">
70
<Label for="card-spacing-email">Email</Label>
71
<Input id="card-spacing-email" type="email" placeholder="m@example.com" required />
72
</div>
73
<div class="grid gap-2">
74
<div class="flex items-center">
75
<Label for="card-spacing-password">Password</Label>
76
<a
77
href="/docs"
78
class="ml-auto inline-block text-sm underline-offset-4 hover:underline"
79
>
80
Forgot your password?
81
</a>
82
</div>
83
<Input id="card-spacing-password" type="password" required />
84
</div>
85
</div>
86
</form>
87
</CardContent>
88
<CardFooter class="flex-col gap-2">
89
<Button type="submit" class="w-full">
90
Login
91
</Button>
92
<Button variant="outline" class="w-full">
93
Login with Google
94
</Button>
95
</CardFooter>
96
</Card>
97
</div>
98
);
99
}

Use negative margins with -mx-(--card-spacing) to make content edge-to-edge while keeping it aligned with the card inset.

Terms of Service
Review the terms before accepting the agreement.

These terms govern your use of the workspace, including access to shared documents, project files, and collaboration tools.

You are responsible for the content you upload and for ensuring that your team has the appropriate permissions to view or edit it.

We may update features or limits as the service evolves. When those changes materially affect your workflow, we will notify your workspace administrators.

By continuing, you agree to keep your account credentials secure and to follow your organization's acceptable use policies.

1
import { Button } from "~/components/ui/button";
2
import {
3
Card,
4
CardContent,
5
CardDescription,
6
CardFooter,
7
CardHeader,
8
CardTitle,
9
} from "~/components/ui/card";
10
11
export default function CardEdgeToEdge() {
12
return (
13
<Card class="mx-auto w-full max-w-sm">
14
<CardHeader>
15
<CardTitle>Terms of Service</CardTitle>
16
<CardDescription>Review the terms before accepting the agreement.</CardDescription>
17
</CardHeader>
18
<CardContent class="-mb-(--card-spacing)">
19
<div class="-mx-(--card-spacing) max-h-48 space-y-4 overflow-y-scroll border-t bg-muted/50 px-(--card-spacing) py-4 text-sm leading-relaxed">
20
<p>
21
These terms govern your use of the workspace, including access to shared documents,
22
project files, and collaboration tools.
23
</p>
24
<p>
25
You are responsible for the content you upload and for ensuring that your team has the
26
appropriate permissions to view or edit it.
27
</p>
28
<p>
29
We may update features or limits as the service evolves. When those changes materially
30
affect your workflow, we will notify your workspace administrators.
31
</p>
32
<p>
33
By continuing, you agree to keep your account credentials secure and to follow your
34
organization&apos;s acceptable use policies.
35
</p>
36
</div>
37
</CardContent>
38
<CardFooter class="justify-end gap-2">
39
<Button variant="outline">Decline</Button>
40
<Button>Accept</Button>
41
</CardFooter>
42
</Card>
43
);
44
}

Image

Add an image before the card header to create a card with an edge-to-edge image.

Event cover
Featured
Design systems meetup
A practical talk on component APIs, accessibility, and shipping faster.
1
import { Badge } from "~/components/ui/badge";
2
import { Button } from "~/components/ui/button";
3
import {
4
Card,
5
CardAction,
6
CardDescription,
7
CardFooter,
8
CardHeader,
9
CardTitle,
10
} from "~/components/ui/card";
11
12
export default function CardImage() {
13
return (
14
<Card class="relative mx-auto w-full max-w-sm pt-0">
15
<div class="absolute inset-0 z-30 aspect-video bg-black/35" />
16
<img
17
src="https://avatar.vercel.sh/shadcn1"
18
alt="Event cover"
19
class="relative z-20 aspect-video w-full object-cover brightness-60 grayscale dark:brightness-40"
20
/>
21
<CardHeader>
22
<CardAction>
23
<Badge variant="secondary">Featured</Badge>
24
</CardAction>
25
<CardTitle>Design systems meetup</CardTitle>
26
<CardDescription>
27
A practical talk on component APIs, accessibility, and shipping faster.
28
</CardDescription>
29
</CardHeader>
30
<CardFooter>
31
<Button class="w-full">View Event</Button>
32
</CardFooter>
33
</Card>
34
);
35
}

API Reference

Card

The root container for card content.

PropTypeDefault
size"default" | "sm""default"
classstring-

CardHeader

Contains a title, description, and optional action.

PropTypeDefault
classstring-

CardTitle

The card title.

PropTypeDefault
classstring-

CardDescription

Helper text displayed under the title.

PropTypeDefault
classstring-

CardAction

Places content in the top-right of the header.

PropTypeDefault
classstring-

CardContent

The main card body.

PropTypeDefault
classstring-

CardFooter

Actions or secondary content displayed at the bottom of the card.

PropTypeDefault
classstring-

Changelog

Spacing Variable

If you're upgrading from a previous version of the Card component, apply the following updates to use the --card-spacing variable.

Update the Card root spacing classes.

Replace the hard-coded gap and vertical padding with --card-spacing, and set the default and small size values on the root:

gap-6 py-6 data-[size=sm]:gap-4 data-[size=sm]:py-4
gap-(--card-spacing) py-(--card-spacing) [--card-spacing:--spacing(6)] data-[size=sm]:[--card-spacing:--spacing(4)]

Update CardHeader spacing classes.

Replace the horizontal padding and border spacing with the shared variable:

px-6 group-data-[size=sm]/card:px-4 [.border-b]:pb-6 group-data-[size=sm]/card:[.border-b]:pb-4
px-(--card-spacing) [.border-b]:pb-(--card-spacing)

Update CardContent and CardFooter spacing classes.

Use --card-spacing for the content inset and footer padding:

px-6 group-data-[size=sm]/card:px-4
px-(--card-spacing)
px-6 group-data-[size=sm]/card:px-4 [.border-t]:pt-6 group-data-[size=sm]/card:[.border-t]:pt-4
px-(--card-spacing) [.border-t]:pt-(--card-spacing)

After applying these changes, customize card spacing by setting --card-spacing on the Card with an arbitrary property class:

function Example() {
return <Card class="[--card-spacing:--spacing(6)]">...</Card>;
}

On This Page

  • Installation
  • Usage
  • Composition
  • Size
  • Spacing
  • Image
  • API Reference
    • Card
    • CardHeader
    • CardTitle
    • CardDescription
    • CardAction
    • CardContent
    • CardFooter
  • Changelog
    • Spacing Variable
Built by Kevin Abatan. The source code is available on GitHub.