npx shadcn@latest add https://sdk-components.thesqd.com/r/card.jsonimport { Card } from "@/components/ui/card";import { Card } from "@/components/ui/card";
export function Example() {
return (
<Card
title="Heads up"
description="You can add components to your app using the squad-ui CLI."
>
Card content goes here.
</Card>
);
}Card (single component — pass content as props)
├── icon={LucideIcon} (optional — FeaturedIcon above the title)
│ ├── iconColor="brand" (color token; default "brand")
│ ├── iconVariant="gradient" (gradient | flat; default "gradient")
│ └── iconSize="lg" (sm | md | lg | xl | 2xl; default "lg")
├── title={<ReactNode>} (renders into the header title slot)
├── description={<ReactNode>} (multi-line / JSX is fine)
├── action={<Button … />} (optional — top-right of the header)
├── footer={<ReactNode>} (optional — bordered footer strip)
├── type="default" | "comment" | "image-card" | "toolbar"
├── count={3} (type="toolbar" — the pill beside the title)
├── countColor="warning" (type="toolbar" — tints that pill)
├── link={{ label, href }} (type="toolbar" — link button + right arrow, band's right end)
├── linkAs={Link} (type="toolbar" — your router's link; default <a>)
├── header="band" | "label" (type="toolbar" — shaded band, or the project viewer's quiet label)
├── iconMuted (type="toolbar" — the header icon in the muted colour, for an empty card)
├── collapsible / open / onOpenChange (type="toolbar" — the band folds the body, caret on the right)
├── headerless / headerProps (type="toolbar" — no band / props for the band)
├── bodyClassName="…" (type="toolbar" — the padded body's classes)
├── image={url | <Image/>} (type="image-card" — full-bleed media at the top)
├── imageAlt="…" (alt text when image is a URL)
├── ratio="W:H" | "W/H" (type="image-card" — aspect ratio of the WHOLE card; image fills the remaining space)
├── imageRatio="W:H" | "W/H" (type="image-card" — aspect ratio of just the image; default "16:9"; ignored when ratio is set)
├── href="…" (type="image-card" — makes the whole card a clickable <a>; pair with target / rel)
├── onClick={fn} (makes the whole card interactive — cursor-pointer, hover shadow, focus ring, keyboard activation)
├── tag={"New" | <Badge …/>} (type="image-card" — overlay badge in the top-left of the image)
├── showCornerTab (pins a corner tab tinted to match the card outline)
├── cornerTabContent={text | <Comp/>} (tab contents — string or any ReactNode)
├── cornerTabPosition="top-right" (top-right | top-left | bottom-right | bottom-left)
├── cornerTabClassName="…" (override the tab's padding / text / background)
├── cornerTabIcon={<Icon/>} (collapsed-state glyph)
├── cornerTabExpandOnHover (square → label on card hover)
├── onCornerTabClick={fn} (tab becomes a <button>)
├── children (auto-wrapped in <CardContent> unless contentWrapper="none")
├── size="default" | "sm"
└── contentWrapper="card-content" | "none"
Need a non-standard layout (e.g. an image-only card, custom header grid, or
two stacked content sections)? The slot exports — CardHeader, CardTitle,
CardDescription, CardAction, CardContent, CardFooter — are still exported
from the same file as an escape hatch. Drop the prop API for that one card
and compose the slots directly.action slots a secondary control into the top-right of the header.size="sm" tightens the paddings and shrinks the title.A plain `count` wears the band's neutral pill.
True Hope Church
Pacific · Account 4114
Booklet · Awaiting Feedback · 2d
$29/mo
$79/mo
| Prop | Type | Default | Description |
|---|---|---|---|
title | ReactNode | — | Heading rendered inside the auto-emitted CardHeader. |
description | ReactNode | — | Subheading. Accepts strings or JSX (multi-line, links, code). |
icon | ComponentType<{ className?: string }> | — | Lucide icon (or any `({ className }) => JSX`) rendered as a `FeaturedIcon` above the title. |
iconColor | FeaturedIconColor | "brand" | Color token for the `icon`'s FeaturedIcon. |
iconVariant | "gradient" | "flat" | "gradient" | Surface treatment for the `icon`'s FeaturedIcon. |
iconSize | "sm" | "md" | "lg" | "xl" | "2xl" | "lg" | Size of the `icon`'s FeaturedIcon. |
action | ReactNode | — | Top-right slot inside the header — typically a small button or link. |
footer | ReactNode | — | Footer strip. Wrap multiple buttons in a flex row to align them. |
size | "default" | "sm" | "default" | `sm` tightens paddings and shrinks the title — good for dense grids. |
contentWrapper | "card-content" | "none" | "card-content" | When the prop API is in use, children are wrapped in `<CardContent>` by default. Set to `"none"` to render them inline (no padding). |
type | "default" | "comment" | "image-card" | "toolbar" | "default" | `image-card` swaps the layout for a full-bleed image at the top with a controllable aspect ratio, then title + description below. `comment` renders an avatar + name + time header. `toolbar` draws the data grid's header band over a padded body. |
image | string | ReactNode | — | `type="image-card"` — image URL (rendered as `<img>` with `object-cover`) or any ReactNode (e.g. `<Image>` from next/image). |
imageAlt | string | — | Alt text used when `image` is a URL. |
ratio | string | — | `type="image-card"` — aspect ratio for the **whole card** (image + caption). Accepts `"W:H"` / `"W/H"`. When set, the image fills the remaining space above the caption. Leave undefined for auto-height. |
imageRatio | string | "16:9" | `type="image-card"` — aspect ratio for the **image** only. Accepts `"W:H"` / `"W/H"` (e.g. `"4:3"`, `"1:1"`). Ignored when `ratio` is set. |
href | string | — | `type="image-card"` — makes the entire card a clickable link (renders as `<a>`). Pair with `target` / `rel` as needed. Adds a hover shadow + subtle image zoom. |
target | HTMLAttributeAnchorTarget | — | Anchor target when `href` is set. |
rel | string | — | Anchor rel when `href` is set. |
tag | ReactNode | — | `type="image-card"` — overlay badge in the top-left corner of the image. Pass a string for a default `<Badge>` or any ReactNode (e.g. `<Badge variant="secondary">…</Badge>`) for full control. |
showCornerTab | boolean | false | Render a small corner tab clipped to one corner of the card, tinted to match the card's outline (`ring-foreground/10`). Requires `cornerTabContent`. |
cornerTabContent | ReactNode | — | Content shown inside the corner tab. Pass a string/number for the default styled tab, or any ReactNode (including your own component). |
cornerTabPosition | "top-right" | "top-left" | "bottom-right" | "bottom-left" | "top-right" | Which corner the tab sits in. |
cornerTabClassName | string | — | Extra classes for the tab element — override its padding, text, or background. |
cornerTabIcon | ReactNode | — | Glyph shown in the collapsed tab. With `cornerTabExpandOnHover` the tab stays a square holding just this icon until the card is hovered. |
cornerTabExpandOnHover | boolean | false | Collapse the tab to `cornerTabIcon` and glide it open on card hover/focus, revealing `cornerTabContent` as a label. Requires `cornerTabIcon`. |
onCornerTabClick | (e: MouseEvent) => void | — | Makes the tab a real `<button>` with its own click handler, hover tint, and focus ring — independent of the card's `onClick`. |
count | ReactNode | — | `type="toolbar"` — the figure beside the title, in the band's neutral pill. Pass the figure (or an animated one), never a `<Badge>` — the card draws the pill. |
countColor | "success" | "warning" | "destructive" | "info" | "muted" | "brand" | — | `type="toolbar"` — tints the count pill with a status tone (one pill, not a badge inside a pill). |
link | { label: ReactNode; href: string } | — | `type="toolbar"` — a link button with a right arrow at the band's right end, after `action`. |
linkAs | ElementType | "a" | `type="toolbar"` — what `link` renders as. Pass your router's link (Next's `Link`) for client-side navigation. |
header | "band" | "label" | "band" | `type="toolbar"` — `band` is the shaded records-toolbar band; `label` is the project viewer's quiet header: a small muted name beside a brand-coloured icon, no fill, no divider, padded to match the body. |
iconTone | "muted" | "coral" | — | `type="toolbar"` — the header icon's tone: `muted` (same as `iconMuted`) or `coral`, the attention colour — e.g. a list icon that turns coral while something in it needs doing. |
iconMuted | boolean | false | `type="toolbar"` — draws the header's icon in the muted text colour instead of the header's colour. For a quiet card with nothing in it ("Nothing waiting on you"), so the icon does not call attention to an empty answer. |
collapsible | boolean | false | `type="toolbar"` — the whole band becomes a button that folds the body away, with a caret at its right end. Don't combine with `link` (an `<a>` can't sit inside a `<button>`). |
open / defaultOpen / onOpenChange | boolean / boolean / (open: boolean) => void | — / true / — | `type="toolbar"` + `collapsible` — control the fold, or let it keep its own state. |
fill | boolean | false | `type="toolbar"` — stretch to the height the parent gives it instead of hugging the content; the body flexes so what scrolls inside takes the rest. A folded collapsible card still shrinks to its band. |
headerless | boolean | false | `type="toolbar"` — draw no band, just the surface and the body. |
headerProps | ComponentProps<"div"> | — | `type="toolbar"` — extra props for the band: a drag-handle class, an aria-label. |
bodyClassName | string | — | `type="toolbar"` — classes for the padded body (`p-3`, clipped, by default). `contentWrapper="none"` drops the body wrapper entirely; no `children` at all leaves the band standing on its own. |
onClick | (e) => void | — | Click handler. On any card it makes the whole surface interactive — adds `cursor-pointer`, a hover shadow, a focus ring, and keyboard activation (Enter/Space) with `role="button"`. |
className | string | — | Override or extend the resolved Card classes. |