Skip to content

Card

Composable card (Card, CardHeader, CardKicker, CardTitle, CardDescription, CardContent, CardFooter) with 5 solid tones, 3 hard-shadow depths and an interactive press-on-hover mode.

brutalist/ui/card
Open ↗

Source

import type { HTMLAttributes, ReactNode } from "react";
import { cn } from "@/lib/utils";

export type CardTone = "surface" | "primary" | "secondary" | "accent" | "ink";

const TONES: Record<CardTone, string> = {
  surface: "bg-da-surface text-da-surface-fg",
  primary: "bg-da-primary text-da-primary-fg",
  secondary: "bg-da-secondary text-da-secondary-fg",
  accent: "bg-da-accent text-da-accent-fg",
  ink: "bg-da-fg text-da-bg",
};

export interface CardProps extends HTMLAttributes<HTMLDivElement> {
  tone?: CardTone;
  /** Adds the hard shadow + press-on-hover behaviour (use when the whole card is clickable). */
  interactive?: boolean;
  shadow?: "none" | "sm" | "md" | "lg";
}

export function Card({ tone = "surface", interactive = false, shadow = "md", className, ...props }: CardProps) {
  return (
    <div
      className={cn(
        "da-stroke flex flex-col",
        TONES[tone],
        shadow === "sm" && "shadow-da-sm",
        shadow === "md" && "shadow-da-md",
        shadow === "lg" && "shadow-da-lg",
        interactive &&
          "da-transition focus-within:translate-x-[3px] focus-within:translate-y-[3px] hover:translate-x-[6px] hover:translate-y-[6px] hover:shadow-none",
        className,
      )}
      {...props}
    />
  );
}

export function CardHeader({ className, ...props }: HTMLAttributes<HTMLDivElement>) {
  return <div className={cn("flex flex-col gap-1.5 p-5 sm:p-6", className)} {...props} />;
}

export function CardKicker({ className, ...props }: HTMLAttributes<HTMLParagraphElement>) {
  return <p className={cn("font-da-mono text-[11px] font-bold tracking-da-label uppercase opacity-75", className)} {...props} />;
}

export function CardTitle({ className, as: Tag = "h3", ...props }: HTMLAttributes<HTMLHeadingElement> & { as?: "h2" | "h3" | "h4" }) {
  return <Tag className={cn("font-da-display text-xl leading-tight tracking-da-display uppercase", className)} {...props} />;
}

export function CardDescription({ className, ...props }: HTMLAttributes<HTMLParagraphElement>) {
  return <p className={cn("text-sm leading-relaxed opacity-80", className)} {...props} />;
}

export function CardContent({ className, ...props }: HTMLAttributes<HTMLDivElement>) {
  return <div className={cn("flex-1 px-5 pb-5 sm:px-6 sm:pb-6", className)} {...props} />;
}

export function CardFooter({ className, children, ...props }: HTMLAttributes<HTMLDivElement> & { children?: ReactNode }) {
  return (
    <div className={cn("flex items-center gap-3 border-t-[length:var(--da-border-width)] border-current px-5 py-4 sm:px-6", className)} {...props}>
      {children}
    </div>
  );
}

export default Card;

modules/brutalist/ui/card/index.tsx

Props

PropTypeDefaultDescription
tone"surface" | "primary" | "secondary" | "accent" | "ink""surface"Background/foreground pair.
shadow"none" | "sm" | "md" | "lg""md"Hard shadow depth.
interactivebooleanfalsePress into the shadow on hover/focus-within. Wrap the card in a link or button yourself.
...restHTMLAttributes<HTMLDivElement>—Native div attributes.
CardTitle.as"h2" | "h3" | "h4""h3"Heading level of the title.

Other card variants in Brutalist

Card in other art directions

Card

Composable frosted card (Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter) with frosted / tinted-gradient / solid variants, specular top edge and interactive lift.

GlassCard

Meeting Card

Meeting recap glass card: title, time / duration / platform meta, gradient participant stack with +N, AI summary panel, action items with checkboxes and owners, and a transcript link.

GlassCard

Profile Card

Teammate glass card: gradient cover, large initials avatar with presence dot, role and timezone, status pill, three stats, expertise tags and Message / Schedule actions.

GlassCard

Stat Ring Card

KPI glass card with a primary→accent gradient progress ring (SVG) showing the percentage, the value over its max and a caption; the ring draws in on mount.

GlassCard

Card

Composable hairline card (Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter) with default / raised / ghost variants and an interactive hover lift.

MinimalCard

Incident Card

Incident summary card: severity chip, id and duration, linked title, service chips, a 4-step status progress bar, commander avatar, stacked responder avatars and update count.

MinimalCard

Integration Card

Integration tile: logo/monogram, name, category, description, a Radix Switch to enable it, live status meta and a Configure link. Controlled or uncontrolled.

MinimalCard

Metric Card

KPI card: muted label, big mono value, inline SVG sparkline with area fill and end dot, and a colored delta chip vs. the previous period (lowerIsBetter flips the colors).

MinimalCard

Profile Card

Studio/person profile card in the Read.cv spirit: square gray portrait with initials, name, role and city in mono, availability dot in signal color, short bio and a list of links with ↗.

Mono CleanCard

Project Card

Portfolio project card: neutral image frame that darkens slightly on hover with a “View case ↗” overlay, then a mono meta row (index, client, year) and the title with discipline tags.

Mono CleanCard

Stat Card

Analytics stat: mono label, large display value, change in mono, and a row of thin vertical bars (last bar in ink, others gray) — no chart chrome.

Mono CleanCard

Template Card

Template tile: a wireframe preview drawn with hairlines (nav, giant title, image grid) in a bordered frame, then name, author, category and usage count, with a “Use template” button revealed on hover/focus.

Mono CleanCard

Account Card

Bank account card: institution + masked number header, big balance with available amount, sync timestamp, and three recent inflow/outflow rows.

Neo CorporateCard

Invoice Card

Invoice summary card: number + status, bill-to and dates grid, line items table with mono amounts, subtotal/tax/total, and download/send actions.

Neo CorporateCard

Kpi Card

Metric card: label, big mono value, colored delta vs. period and an area sparkline in the primary color along the bottom.

Neo CorporateCard

Plan Card

Billing/subscription card: current plan + price + renewal date, usage meters (progressbar semantics, turning amber at 80% and red at 95%), manage and upgrade actions.

Neo CorporateCard

Action Card

Reduction action card: serif title, description, saving and cost figures, leaf-rated impact/effort, and an “Add to plan” pill that toggles to a sage “In your plan” state.

Organic SoftCard

Article Card

Journal article card: an organic shaped “cover” (arch, blob or circle) with a hand-drawn leaf, category and read time, serif title that underlines on hover, excerpt; whole card is one link.

Organic SoftCard

Metric Card

Emissions metric card: label, big serif value with mono unit, a change chip (down = good, sage; up = clay) and a human equivalence line with a small leaf.

Organic SoftCard

Supplier Card

Supplier card: arch-shaped initials avatar, name, category and country, status pill, share of your footprint and a rounded data-completeness bar with a reminder action.

Organic SoftCard

Profile Card

Rounded teammate card: pastel header band, big emoji avatar in a white circle, name, role, status pill, three stats in soft wells, skill pills and a “Say hi” button.

Soft FlatCard

Project Card

Pastel project card: white emoji tile, name link covering the card, description, chunky rounded progress bar with percentage, tasks-left and due chips, member dots.

Soft FlatCard

Stat Card

Friendly KPI tile: emoji in a white circle, change pill, label, big rounded number and a row of rounded mini bars (last one highlighted); five tones.

Soft FlatCard

Task Card

Kanban task card: round done checkbox with bouncy tick, pastel label, title (struck when done), subtask progress, due chip that turns red when overdue, comment/attachment counts and avatar dots.

Soft FlatCard