Skip to content

ContainersCard

Card

The default content container. A card groups a title, body, and optional action under a single border.

2 tonesOptional icon1 px line, not a shadow

Demo

The default card has a 1 px --line-strong border, 4 px radius, and no shadow. The shadow is reserved for overlays.

Default

A worked example

A card groups a title, body, and optional action under a single border.

Read more

With icon

With icon

Foundations

The tokens. Color, type, space, motion, and the rest of the language.

Tones

Tones

Default surface

Cream on the page, slightly lighter than the page itself.

Inset surface

Slightly darker than the page, used for code blocks and table rows.

Anatomy

  • 1 px --line-strong border, 4 px radius
  • --surface-elevated background (or --surface-inset for the inset tone)
  • Padding: 24 px (default), 16 px in dense lists
  • Title is set in display, 1.5 rem / 1.15 line-height
  • Body is set in body, 0.9375 rem / 1.6 line-height
  • No shadow. The card sits on the page; only overlays have shadows.

Implementation

card.tsx
import { type ElementType, type ReactNode } from "react"
import { cn } from "@/lib/utils"
import SiteIcon, type SiteIconProps } from "@/components/site-icon"

interface CardProps {
  title?: string
  icon?: SiteIconProps["icon"]
  tone?: "default" | "inset"
  as?: ElementType
  className?: string
  children: ReactNode
}

export function Card({ title, icon, tone = "default", as: As = "div", className, children }: CardProps) {
  return (
    <As className={cn("ds-card", tone === "inset" && "ds-card--inset", className)}>
      {icon ? (
        <div className="ds-card__icon-wrap">
          <SiteIcon icon={icon} size="md" tone="emphasis" />
        </div>
      ) : null}
      {title ? <h3 className="ds-card__title">{title}</h3> : null}
      {children}
    </As>
  )
}

Props

PropTypeDefaultDescription
titlestringNoneOptional title
iconLucideIconNoneOptional icon, top-left
tone"default" | "inset""default"Surface tone
asElementType"div"Render as a different element