Skip to content

DiagramsBuilding a new diagram

Building a new diagram

A 5-step recipe for adding a diagram to a case study. Each step is short; the recipe is the same for every diagram.

5 steps1 component file1 CSS file (if new)

The recipe

  1. Write the sentence. Before you touch a file, write the one-sentence argument the diagram will make. If you can't write it in one sentence, the diagram is doing two things.
  2. Choose the kind. Sequence, structure, or comparison. The kind is determined by the argument, not the page.
  3. Build the component file. One file in app/work/[case-study]/diagrams/. The file exports a single component, named after the diagram.
  4. Add the CSS. If the diagram needs new layout, add it to study-diagrams.css, scoped under .study-case. Otherwise, no CSS is needed.
  5. Test on 360 px and 1280 px. The diagram must read on a phone and on a desktop. If it doesn't, the diagram is wrong, not the breakpoint.

The skeleton

diagrams/example.tsx
import { DiagramPanel } from "./diagram-panel"

const items = [
  { label: "...", note: "...", tone: "light" as const },
  { label: "...", note: "...", tone: "dark" as const },
]

export function ExampleDiagram() {
  return (
    <figure className="study-diagram">
      <header className="study-diagram__head">
        <p className="study-diagram__eyebrow">Sequence</p>
        <h3 className="study-diagram__title">A worked example of a new diagram</h3>
      </header>
      <div className="study-diagram__steps">
        {items.map((item, i) => (
          <div key={item.label} className="study-diagram__step">
            <DiagramPanel
              tone={item.tone}
              eyebrow={`Step 0${i + 1}`}
              title={item.label}
            />
            <p className="study-diagram__step-note">{item.note}</p>
          </div>
        ))}
      </div>
    </figure>
  )
}

The DiagramPanel

Every diagram in the system reuses the DiagramPanel component. The component is the visual primitive that holds a tone, an eyebrow, a title, and (optionally) a body.

diagram-panel.tsx
interface DiagramPanelProps {
  tone?: "light" | "dark" | "accent"
  eyebrow: string
  title: string
  children?: React.ReactNode
}

export function DiagramPanel({ tone = "light", eyebrow, title, children }: DiagramPanelProps) {
  return (
    <div className={`study-diagram__panel study-diagram__panel--${tone}`}>
      <p className="study-diagram__panel-eyebrow">{eyebrow}</p>
      <h4 className="study-diagram__panel-title">{title}</h4>
      {children}
    </div>
  )
}

The review checklist

  • The diagram makes a single, specific argument. The argument is in the prose above the diagram.
  • All tones are used at most once per diagram. (light = default, dark or accent = the moment)
  • The diagram works at 360 px wide. The text is readable; nothing is cut off.
  • The diagram works at 1280 px wide. The five steps are on one row, the heights match.
  • The diagram is keyboard-accessible. The text inside is real text, not images.
  • The diagram respects prefers-reduced-motion. (No animation is the default.)

What not to do