Card
A flexible container for grouping related content and actions.
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
const CardDemo = () => (
<Card className="w-[360px]">
<CardHeader>
<CardTitle>Create project</CardTitle>
<CardDescription>Deploy your new project in one-click.</CardDescription>
</CardHeader>
<CardContent>
<p className="text-muted-foreground">
Fill in your project details to get started with deployment.
</p>
</CardContent>
<CardFooter className="justify-end gap-2">
<Button variant="outline">Cancel</Button>
<Button>Deploy</Button>
</CardFooter>
</Card>
);
export default CardDemo;
Installation
npx shadcn@latest add @ark-cn/cardInstall the dependency required by this primitive:
npm install @ark-ui/reactCopy the component source into your app:
TSXcomponents/ui/card.tsx
"use client";
import { ark } from "@ark-ui/react/factory";
import * as React from "react";
import { cn } from "@/lib/utils";
const Card = ({
className,
size = "default",
...props
}: React.ComponentProps<typeof ark.div> & { size?: "default" | "sm" }) => (
<ark.div
data-slot="card"
data-size={size}
className={cn(
"group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
className,
)}
{...props}
/>
);
const CardHeader = ({
className,
...props
}: React.ComponentProps<typeof ark.div>) => (
<ark.div
data-slot="card-header"
className={cn(
"group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3",
className,
)}
{...props}
/>
);
const CardTitle = ({
className,
...props
}: React.ComponentProps<typeof ark.div>) => (
<ark.div
data-slot="card-title"
className={cn(
"cn-font-heading text-base leading-snug font-medium group-data-[size=sm]/card:text-sm",
className,
)}
{...props}
/>
);
const CardDescription = ({
className,
...props
}: React.ComponentProps<typeof ark.div>) => (
<ark.div
data-slot="card-description"
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
);
const CardAction = ({
className,
...props
}: React.ComponentProps<typeof ark.div>) => (
<ark.div
data-slot="card-action"
className={cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
className,
)}
{...props}
/>
);
const CardContent = ({
className,
...props
}: React.ComponentProps<typeof ark.div>) => (
<ark.div
data-slot="card-content"
className={cn("px-4 group-data-[size=sm]/card:px-3", className)}
{...props}
/>
);
const CardFooter = ({
className,
...props
}: React.ComponentProps<typeof ark.div>) => (
<ark.div
data-slot="card-footer"
className={cn(
"flex items-center rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/card:p-3",
className,
)}
{...props}
/>
);
export {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
};
Update import aliases to match your project setup.
Usage
import {
Card,
CardHeader,
CardFooter,
CardTitle,
CardAction,
CardDescription,
CardContent,
} from "@/components/ui/card"<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
<CardDescription>Description</CardDescription>
</CardHeader>
<CardContent>Content goes here.</CardContent>
<CardFooter>Footer</CardFooter>
</Card>Examples
Default
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
const CardDemo = () => (
<Card className="w-[360px]">
<CardHeader>
<CardTitle>Create project</CardTitle>
<CardDescription>Deploy your new project in one-click.</CardDescription>
</CardHeader>
<CardContent>
<p className="text-muted-foreground">
Fill in your project details to get started with deployment.
</p>
</CardContent>
<CardFooter className="justify-end gap-2">
<Button variant="outline">Cancel</Button>
<Button>Deploy</Button>
</CardFooter>
</Card>
);
export default CardDemo;
Simple
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
const CardSimple = () => (
<Card className="w-[360px]">
<CardHeader>
<CardTitle>Notifications</CardTitle>
<CardDescription>You have 3 unread messages.</CardDescription>
</CardHeader>
<CardContent>
<p className="text-muted-foreground">
Check your inbox to see the latest updates from your team.
</p>
</CardContent>
</Card>
);
export default CardSimple;
With Action
import { Button } from "@/components/ui/button";
import {
Card,
CardAction,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
const CardWithAction = () => (
<Card className="w-[360px]">
<CardHeader>
<CardTitle>Team Members</CardTitle>
<CardDescription>Manage your team and permissions.</CardDescription>
<CardAction>
<Button size="sm" variant="outline">
Invite
</Button>
</CardAction>
</CardHeader>
<CardContent>
<p className="text-muted-foreground">
You currently have 4 team members with access to this project.
</p>
</CardContent>
</Card>
);
export default CardWithAction;
Small
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
const CardSmall = () => (
<Card size="sm" className="w-[320px]">
<CardHeader>
<CardTitle>Quick Note</CardTitle>
<CardDescription>Compact card variant.</CardDescription>
</CardHeader>
<CardContent>
<p className="text-muted-foreground">
Use the sm size for denser layouts.
</p>
</CardContent>
<CardFooter className="justify-end">
<Button size="sm">Save</Button>
</CardFooter>
</Card>
);
export default CardSmall;
API Reference
This component is an ark-cn composition. All parts render as ark.div elements.
Card
| Prop | Type | Default | Description |
|---|---|---|---|
size | "default" | "sm" | "default" | Controls spacing density across all child parts via group-data-[size=sm]. |
className | string | — | Additional class names merged via cn(). |
CardHeader
Grid container for title, description, and optional action. Adjusts column layout automatically when CardAction is present.
CardTitle
Heading text. Scales with the size prop inherited from Card.
CardDescription
Muted secondary text below the title.
CardAction
Pinned to the top-right of the header grid. Spans two rows to align with both title and description.
CardContent
Main body area. Horizontal padding matches the card size.
CardFooter
Muted bottom bar with a top border. Padding matches the card size.