Skip to content
EMBOSS
Docs menu

Card

A surface for grouped content with three seatings: raised off the page, flush with it, or recessed into a well.

@emboss/card
Calibration
Name this preset before writing it to memory.

Installation

pnpm dlx shadcn@latest add @emboss/card

Usage

example.tsx
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";

export function Example() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Output level</CardTitle>
        <CardDescription>Master bus, post-fader.</CardDescription>
      </CardHeader>
      <CardContent>Signal is nominal.</CardContent>
    </Card>
  );
}

Examples

Well

The well variant recesses content into the chassis — built for stats and readouts.

Show code
well.tsx
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";

export default function CardWell() {
  return (
    <Card variant="well" className="w-full max-w-sm">
      <CardHeader>
        <CardTitle className="font-mono text-3xl tabular-nums">
          −6.2 dB
        </CardTitle>
        <CardDescription>Master bus, post-fader peak.</CardDescription>
      </CardHeader>
      <CardContent className="font-mono text-sm text-ink-muted tabular-nums">
        L −6.2 · R −6.8
      </CardContent>
    </Card>
  );
}

API reference

Card

PropTypeDefaultDescription
variant"raised" | "flush" | "well""raised"Seating relative to the page surface: lifted, level, or recessed.

CardHeader / CardTitle / CardDescription / CardContent / CardFooter

Layout parts. Each renders a div with a data-slot attribute for styling hooks.

Source

View source — card.tsx
card.tsx
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";

const cardVariants = cva("flex flex-col gap-6 rounded-lg py-6 text-ink", {
  variants: {
    variant: {
      /** A tray raised off the surface. */
      raised: "bg-surface-2 shadow-emboss-1",
      /** Level with the surface; just the machined edge. */
      flush: "bg-surface-1 shadow-flush",
      /** A recessed pocket, for stats and readouts. */
      well: "bg-well shadow-deboss-1",
    },
  },
  defaultVariants: {
    variant: "raised",
  },
});

export type CardProps = React.ComponentProps<"div"> &
  VariantProps<typeof cardVariants>;

/**
 * A surface for grouped content. Raised by default; `flush` sits level with
 * the page and `well` recesses into it.
 *
 * @example
 * <Card>
 *   <CardHeader>
 *     <CardTitle>Output level</CardTitle>
 *     <CardDescription>Master bus, post-fader.</CardDescription>
 *   </CardHeader>
 *   <CardContent>…</CardContent>
 * </Card>
 */
function Card({ className, variant, ...props }: CardProps) {
  return (
    <div
      data-slot="card"
      className={cn(cardVariants({ variant }), className)}
      {...props}
    />
  );
}

function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-header"
      className={cn("grid auto-rows-min items-start gap-1.5 px-6", className)}
      {...props}
    />
  );
}

function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-title"
      className={cn("leading-none font-semibold", className)}
      {...props}
    />
  );
}

function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-description"
      className={cn("text-sm text-ink-muted", className)}
      {...props}
    />
  );
}

function CardContent({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-content"
      className={cn("px-6", className)}
      {...props}
    />
  );
}

function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-footer"
      className={cn("flex items-center gap-2 px-6", className)}
      {...props}
    />
  );
}

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