p441z/Components/Card
UI · components/ui/card.tsx

Card

The base surface, in six composable parts.

110 linesGitHub ↗
Install with the shadcn CLI

First time with the kit? Read the install guide

Leave balance

Resets on 1 January.

9 / 12 days

About

Card — the base surface. Composed from six parts so padding and spacing stay consistent no matter what goes inside:

Usage

<Card>
  <CardHeader>
    <CardTitle>Title</CardTitle>
    <CardDescription>Supporting line.</CardDescription>
  </CardHeader>
  <CardContent>…</CardContent>
  <CardFooter><Button>Action</Button></CardFooter>
</Card>

Source

components/ui/card.tsx · 110 lines
import * as React from "react";

import { cn } from "@/lib/utils";

/**
 * Card — the base surface. Composed from six parts so padding and spacing
 * stay consistent no matter what goes inside:
 *
 *   <Card>
 *     <CardHeader>
 *       <CardTitle>Title</CardTitle>
 *       <CardDescription>Supporting line.</CardDescription>
 *     </CardHeader>
 *     <CardContent>…</CardContent>
 *     <CardFooter><Button>Action</Button></CardFooter>
 *   </Card>
 *
 * Note the padding rhythm: Header is `p-6`, while Content and Footer are
 * `p-6 pt-0`. That avoids doubled vertical gaps between stacked sections —
 * the header's bottom padding already separates them.
 *
 * This is the neutral base. For the heavier bordered look used across list
 * and dashboard screens, see the "elevated card" recipe in the README:
 *   rounded-xl border border-neutral-200 bg-white shadow-xs
 *   dark:border-neutral-800 dark:bg-neutral-900/50
 *
 * v4 note: the shadow scale shifted by one step — v3's `shadow` is now
 * `shadow-sm`, and v3's `shadow-sm` is now `shadow-xs`.
 */

const Card = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn(
      "rounded-xl border bg-card text-card-foreground shadow-sm",
      className
    )}
    {...props}
  />
));
Card.displayName = "Card";

const CardHeader = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn("flex flex-col space-y-1.5 p-6", className)}
    {...props}
  />
));
CardHeader.displayName = "CardHeader";

const CardTitle = React.forwardRef<
  HTMLParagraphElement,
  React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
  <h3
    ref={ref}
    className={cn("font-semibold leading-none tracking-tight", className)}
    {...props}
  />
));
CardTitle.displayName = "CardTitle";

const CardDescription = React.forwardRef<
  HTMLParagraphElement,
  React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
  <p
    ref={ref}
    className={cn("text-sm text-muted-foreground", className)}
    {...props}
  />
));
CardDescription.displayName = "CardDescription";

const CardContent = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
));
CardContent.displayName = "CardContent";

const CardFooter = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn("flex items-center p-6 pt-0", className)}
    {...props}
  />
));
CardFooter.displayName = "CardFooter";

export {
  Card,
  CardHeader,
  CardFooter,
  CardTitle,
  CardDescription,
  CardContent,
};