Card

A structured surface with header, content, footer, and actions.

Group forms, summaries, or media on a bordered surface. Compose the sections you need and add CardAction for a control in the header.

Welcome back
Sign in with your work email to continue.
or
tsx
import { Button } from "@/components/ui/button"import {  Card,  CardContent,  CardDescription,  CardFooter,  CardHeader,  CardTitle,} from "@/components/ui/card"export function Example() {  return (    <Card className="w-full max-w-sm">      <CardHeader>        <CardTitle>Welcome back</CardTitle>        <CardDescription>          Sign in with your work email to continue.        </CardDescription>      </CardHeader>      <CardContent>        <form className="flex flex-col gap-4">          <div className="flex flex-col gap-1.5">            <label htmlFor="email" className="text-sm">              Email            </label>            <input              id="email"              type="email"              placeholder="you@company.com"              className="h-9 w-full rounded-md border border-border bg-transparent px-3 text-sm outline-none"            />          </div>          <div className="flex flex-col gap-1.5">            <div className="flex items-center justify-between gap-2">              <label htmlFor="password" className="text-sm">                Password              </label>              <Button variant="link" className="text-xs text-muted-foreground">                Forgot password?              </Button>            </div>            <input              id="password"              type="password"              className="h-9 w-full rounded-md border border-border bg-transparent px-3 text-sm outline-none"            />          </div>        </form>      </CardContent>      <CardFooter className="flex-col gap-3">        <Button className="w-full">Continue</Button>        <div className="flex w-full items-center gap-3 text-xs text-muted-foreground">          <span className="h-px flex-1 bg-border" />          or          <span className="h-px flex-1 bg-border" />        </div>        <Button variant="outline" className="w-full">          Continue with Google        </Button>      </CardFooter>    </Card>  )}

Installation

npx @arctis-sh/@arctis-sh/ui@latest add card

Usage

import {  Card,  CardAction,  CardContent,  CardDescription,  CardFooter,  CardHeader,  CardTitle,} from "@/components/ui/card"
<Card>  <CardHeader>    <CardTitle>Project overview</CardTitle>    <CardDescription>Last synced 2 hours ago</CardDescription>    <CardAction>Edit</CardAction>  </CardHeader>  <CardContent>    <p>12 components published in this namespace.</p>  </CardContent>  <CardFooter>    <p>Updated Jul 30</p>  </CardFooter></Card>

Composition

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

Size

Pass size="sm" when the card needs tighter spacing.

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.
tsx
import { Button } from "@/components/ui/button"import {  Card,  CardContent,  CardDescription,  CardFooter,  CardHeader,  CardTitle,} from "@/components/ui/card"export function Example() {  return (    <Card size="sm" className="w-full max-w-sm">      <CardHeader>        <CardTitle>Scheduled reports</CardTitle>        <CardDescription>          Weekly snapshots. No more manual exports.        </CardDescription>      </CardHeader>      <CardContent>        <ul className="list-disc space-y-1 pl-4 text-sm text-muted-foreground">          <li>Choose a schedule (daily, or weekly).</li>          <li>Send to channels or specific teammates.</li>          <li>Include charts, tables, and key metrics.</li>        </ul>      </CardContent>      <CardFooter className="flex-col gap-2">        <Button size="sm" className="w-full">          Set up scheduled reports        </Button>        <Button size="sm" variant="outline" className="w-full">          See what&apos;s new          <ChevronRightIcon data-icon="inline-end" />        </Button>      </CardFooter>    </Card>  )}

Spacing

Insets and section gaps use --card-spacing. Override it on the card to adjust the density in one place.

Workspace billing
Invoices and seats for your current plan.

12 seats · Pro annual

Next invoice on Aug 1 · $480

tsx
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"export function Example() {  return (    <Card className="w-full max-w-sm [--card-spacing:1.5rem]">      <CardHeader>        <CardTitle>Card Title</CardTitle>      </CardHeader>      <CardContent>Content uses the shared spacing token.</CardContent>    </Card>  )}

Use -mx-[var(--card-spacing)] to extend content to the card edges while keeping the surrounding inset aligned. If the block sits above a footer, add -mb-[var(--card-spacing)] to CardContent to remove the section gap.

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.

tsx
import { Button } from "@/components/ui/button"import {  Card,  CardContent,  CardDescription,  CardFooter,  CardHeader,  CardTitle,} from "@/components/ui/card"export function Example() {  return (    <Card className="w-full max-w-sm">      <CardHeader>        <CardTitle>Terms of Service</CardTitle>        <CardDescription>          Review the terms before accepting the agreement.        </CardDescription>      </CardHeader>      <CardContent className="-mx-[var(--card-spacing)] -mb-[var(--card-spacing)] border-y border-border p-0">        <div className="show-scrollbar max-h-40 space-y-3 overflow-y-auto px-[var(--card-spacing)] py-3 text-sm text-muted-foreground">          <p>These terms govern your use of the workspace…</p>          <p>You are responsible for the content you upload…</p>          <p>We may update features or limits as the service evolves…</p>        </div>      </CardContent>      <CardFooter className="justify-end gap-2">        <Button variant="outline">Decline</Button>        <Button>Accept</Button>      </CardFooter>    </Card>  )}

Image

Place media as the first child of Card, then add pt-0 so it sits flush with the top edge.

Event coverFeatured
Design systems meetup
A practical talk on component APIs, accessibility, and shipping faster.
tsx
import { Badge } from "@/components/ui/badge"import { Button } from "@/components/ui/button"import {  Card,  CardDescription,  CardFooter,  CardHeader,  CardTitle,} from "@/components/ui/card"export function Example() {  return (    <Card className="relative w-full max-w-sm pt-0">      <img        src="/assets/brand/demos/card-cover.png"        alt="Event cover"        className="aspect-video w-full object-cover"      />      <Badge className="absolute top-3 right-3">Featured</Badge>      <CardHeader>        <CardTitle>Design systems meetup</CardTitle>        <CardDescription>          A practical talk on component APIs, accessibility, and shipping          faster.        </CardDescription>      </CardHeader>      <CardFooter>        <Button className="w-full">View Event</Button>      </CardFooter>    </Card>  )}

Action

Put a header control in CardAction to align it to the top-right.

Create an account
Enter your email to get started with the workspace.
tsx
import { Button } from "@/components/ui/button"import {  Card,  CardAction,  CardContent,  CardDescription,  CardFooter,  CardHeader,  CardTitle,} from "@/components/ui/card"export function Example() {  return (    <Card className="w-full max-w-sm">      <CardHeader>        <CardTitle>Create an account</CardTitle>        <CardDescription>          Enter your email to get started with the workspace.        </CardDescription>        <CardAction>          <Button variant="ghost" size="sm">            Sign in          </Button>        </CardAction>      </CardHeader>      <CardContent>        <form className="flex flex-col gap-4">          <div className="flex flex-col gap-1.5">            <label htmlFor="name" className="text-sm">              Name            </label>            <input              id="name"              type="text"              placeholder="Alex Rivera"              className="h-9 w-full rounded-md border border-border bg-transparent px-3 text-sm outline-none"            />          </div>          <div className="flex flex-col gap-1.5">            <label htmlFor="email" className="text-sm">              Email            </label>            <input              id="email"              type="email"              placeholder="you@company.com"              className="h-9 w-full rounded-md border border-border bg-transparent px-3 text-sm outline-none"            />          </div>        </form>      </CardContent>      <CardFooter>        <Button className="w-full">Create account</Button>      </CardFooter>    </Card>  )}

Split

Set the card to flex-row for a side-by-side media layout.

Coastal workshop
A half-day session on shipping design systems with less friction.
tsx
import { Button } from "@/components/ui/button"import {  Card,  CardDescription,  CardFooter,  CardHeader,  CardTitle,} from "@/components/ui/card"export function Example() {  return (    <Card className="w-full max-w-md flex-row gap-0 py-0">      <img        src="/assets/brand/demos/card-cover.png"        alt=""        className="w-28 shrink-0 object-cover sm:w-36"      />      <div className="flex min-w-0 flex-1 flex-col gap-[var(--card-spacing)] py-[var(--card-spacing)]">        <CardHeader>          <CardTitle>Coastal workshop</CardTitle>          <CardDescription>            A half-day session on shipping design systems with less friction.          </CardDescription>        </CardHeader>        <CardFooter>          <Button size="sm">Register</Button>        </CardFooter>      </div>    </Card>  )}

Empty

A dashed border and bg-transparent keep an empty state visually light.

No projects yet
Create a project to start collecting feedback and shipping updates.
tsx
import { Button } from "@/components/ui/button"import {  Card,  CardContent,  CardDescription,  CardHeader,  CardTitle,} from "@/components/ui/card"export function Example() {  return (    <Card className="w-full max-w-sm border-dashed bg-transparent">      <CardHeader>        <CardTitle>No projects yet</CardTitle>        <CardDescription>          Create a project to start collecting feedback and shipping updates.        </CardDescription>      </CardHeader>      <CardContent className="flex justify-end">        <Button size="sm">          Create project        </Button>      </CardContent>    </Card>  )}

Danger

Pair destructive footer actions with direct copy that explains the consequence.

Delete workspace
This permanently removes projects, members, and billing history. This cannot be undone.
tsx
import { Button } from "@/components/ui/button"import {  Card,  CardDescription,  CardFooter,  CardHeader,  CardTitle,} from "@/components/ui/card"export function Example() {  return (    <Card className="w-full max-w-sm">      <CardHeader>        <CardTitle>Delete workspace</CardTitle>        <CardDescription>          This permanently removes projects, members, and billing history. This          cannot be undone.        </CardDescription>      </CardHeader>      <CardFooter className="justify-end gap-2">        <Button variant="outline" size="sm">Cancel</Button>        <Button variant="destructive" size="sm">Delete workspace</Button>      </CardFooter>    </Card>  )}

API Reference

Card

PropTypeDefault
size"default" | "sm""default"
classNamestring
<Card>  <CardHeader>    <CardTitle>Title</CardTitle>    <CardDescription>Subtitle</CardDescription>  </CardHeader>  <CardContent>Body</CardContent></Card>

CardHeader

PropTypeDefault
classNamestring
<CardHeader>  <CardTitle>Title</CardTitle>  <CardDescription>Subtitle</CardDescription></CardHeader>

CardTitle

PropTypeDefault
classNamestring
<CardTitle>Title</CardTitle>

CardDescription

PropTypeDefault
classNamestring
<CardDescription>Subtitle</CardDescription>

CardAction

Places content in the top-right corner of the header.

PropTypeDefault
classNamestring
<CardHeader>  <CardTitle>Title</CardTitle>  <CardAction>    <Button size="sm" variant="outline">Edit</Button>  </CardAction></CardHeader>

CardContent

PropTypeDefault
classNamestring
<CardContent>Body</CardContent>

CardFooter

PropTypeDefault
classNamestring
<CardFooter>  <Button>Save</Button></CardFooter>