← All proposals

Code diff

A recipe, not a component (decided 2026-10-21): a Panel List of changed files, with each row's file icon and name, an optional File Diff (counts and bar), and an expand button that reveals the diff in a Code Block.

Extends a PDS componentOpen in Storybook

proposals/CodeDiff/HANDOFF.md63 lines · View on GitHub

Handoff: Code diff (recipe)

What and why

An agent proposes or applies changes to files, and the person needs to review them in place, in a chat message or an approval report. PDS has the parts (Panel List, Code Block with language='diff', File Diff) but no pattern that puts them together. This is a Panel List of changed files: each row has the file icon and name, an optional File Diff (counts and bar), and an expand button that reveals the diff in a Code Block.

It is a recipe, not a component (2026-10-21): a story and a Usage page that compose existing PDS components. There is nothing to port beyond those components. The engineer copies the composition (see _story-helpers/CodeDiffSample.tsx) and keeps the story as documentation.

  • Figma / Jira: none. Source was Erika's reference image (Diff viewer.png): the list collapsed, the list expanded, and a single expanded file.
  • Context: context.md

Exploration and decisions

  • Composed from the package: PanelList, PanelRow, CodeBlock and FileDiff are all exported, so the recipe composes them. The only new CSS is the file name (code font) and the stats width.
  • The "diff variant" of Code Block is the existing language='diff'. No new Code Block variant.
  • File Diff is optional, shown when both additions and deletions are given. The reference has none; the approval report row had it.
  • Compact rows. The Panel List's paddingSize only sets block padding, and the rows are also held open by a 48px minimum height and 20px side padding in Panel Row that no prop changes. The recipe overrides those (--pds-spacing-2xl minimum height, --pds-spacing-s side padding) and defaults paddingSize to 2xs. Rows go from about 73px to 48px.

API

None: it is a recipe. The sample's inputs are a list of files, each with id, name, diff (unified diff text), optional additions and deletions (they show the File Diff), and expandButtonLabel (the row's expand button name, translated). Options: the Panel List's hasBorder and paddingSize, and the Code Block's copy button.

Tokens used

  • --pds-spacing-2xl
  • --pds-spacing-2xs
  • --pds-spacing-s
  • --pds-typography-ff-code
  • --pds-typography-size-s

Impact

From impact.md: no existing PDS component is reached. The sample's rules, scoped to .code-diff-sample, override .pds-panel-row and .pds-panel-row__main (the compact rows). They apply only inside a Code Diff. No other proposal depends on it.

Reused vs net-new

  • Reused: PanelList, PanelRow, CodeBlock, FileDiff (from the package), and the local Icon wrapper.
  • Net-new: nothing (the sample's code-diff-sample classes are story-only). See custom.md.

Accessibility

  • Each row's expand button takes expandButtonLabel, which names the file. Panel Row owns the expand and collapse semantics and keyboard behavior.
  • The copy button takes copyButtonLabel for its name and tooltip.
  • Diff colors come from the package's Code Block syntax tokens. Added and removed lines should not rely on color alone; check that the + and - markers show.
  • The a11y panel has not been run on these stories. Run it in light and dark before the port.

Decisions and open questions

  • Initially expanded rows. The reference shows rows already expanded, but the package Panel Row starts collapsed and has no prop for it. It needs an isDefaultExpanded on Panel Row, which is a change to the PDS component, not to this one.
  • File icon. fileDiff is a guess from the reference.
  • Row size. A size prop on Panel Row or Panel List would remove the CSS overrides.
  • Diff colors. Check that the added, removed and hunk-header colors match the reference.

Port notes

Nothing to port as a component. Copy the composition from _story-helpers/CodeDiffSample.tsx where it is needed (the nearest home is next to Panel List in src/components/panels/, if the team wants it as a component later). Swap the local Icon wrapper and mergeClasses for the real ones.

Preview

npm run storybook, then Recipes/Code diff.

Figma: https://www.figma.com/design/AMGWJbraJoi2PKWnxo29Ah/PDS-Proposals?node-id=374-46, page Code Diff (2 stories, light only; captures of Storybook with library icons swapped in, sent 2026-10-20).