AI Interface Components

Code Change Explainer

A stepped diff walkthrough: each step highlights removed or added lines while a side note card advances in sync, explaining the change in plain language.

This is a WebberUI Pro component

The install command below needs a licence to run; without one it returns 401.

How to install Pro components →See the plans →

Walk a non-engineer through a code change one step at a time. On the left is a diff window (file name bar, old/new line numbers, code lines); on the right (below on narrow widths) is a note card, with Previous, Next and Auto-play controls along the bottom. On each step, the lines that step mentions get a tinted background and a colored bar on the left edge; removed lines flow away once they have been explained, added lines expand when their step arrives, and every other line fades to 45%, so the eye lands on what this step changed. Each note card carries a line-number badge, and clicking a step or a code line jumps straight to that step.

Bring this into your project

Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.

npx webberui@latest add "https://webberui.com/r/code-change-explainer.en.json?t=<install token>"

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

3200
Active edited usageDefault props
<CodeChangeExplainer/>

The complete example includes the preview layout and data. Install the component first, then paste this file into your project.

Installation

npx webberui@latest add "https://webberui.com/r/code-change-explainer.en.json?t=<install token>"

Or, once registries are configured in components.json, install it as @webberui/code-change-explainer.

Usage

import {
  CodeChangeExplainer,
  type CodeChangeLine,
  type CodeChangeStep,
} from "@/components/ui/code-change-explainer";

const lines: CodeChangeLine[] = [
  { id: "table", type: "add", text: "const FEE = { north: 60, south: 80, islands: 150 };" },
  { id: "sig", type: "context", text: "export function shippingFee(cart: Cart): number {" },
  { id: "fixed", type: "remove", text: "  return 60; // 一律 60 元" },
  { id: "lookup", type: "add", text: "  return FEE[cart.region] ?? 60;" },
  { id: "close", type: "context", text: "}" },
];

const steps: CodeChangeStep[] = [
  { id: "s1", lineIds: ["fixed"], title: "拿掉寫死的 60 元", body: "原本不論寄到哪裡都收 60 元,這行拿掉。" },
  { id: "s2", lineIds: ["table", "lookup"], title: "改成依地區查表", body: "北部 60、南部 80、離島 150。" },
];

<CodeChangeExplainer
  filename="shipping-fee.ts"
  lines={lines}
  steps={steps}
  autoPlay
  onStepChange={(step) => console.log("目前第", step + 1, "步")}
/>;

The Chinese strings in the example are sample data: 一律 60 元 (always 60), 拿掉寫死的 60 元 (drop the fixed 60), 改成依地區查表 (look up the fee by region), 目前第…步 (current step …).

Props

PropTypeDefaultDescription
filenamestring—File name shown in the diff window title bar; shows a generic label when omitted
linesCodeChangeLine[]—All code lines in file order, with removed and added lines interleaved where they belong
stepsCodeChangeStep[]—Walkthrough steps in playback order
stepnumber—Controlled current step (zero-based); managed internally when omitted
defaultStepnumber0Initial step in uncontrolled mode
onStepChange(step: number) => void—Called when the step changes
autoPlaybooleanfalseAuto-play the steps; loops back to the first after the last, and pauses while the pointer is over the component
intervalnumber3200How long each step stays during auto-play (ms), minimum 600
showLineNumbersbooleantrueShow the old/new line-number columns
classNamestring—Passed through to the outermost container

CodeChangeLine

FieldTypeDefaultDescription
idstring—Unique id of the line; steps refer to lines by this id
type"context" | "add" | "remove"—Unchanged context, added, or removed
textstring—Raw text of the line (indentation preserved)

CodeChangeStep

FieldTypeDefaultDescription
idstring—Unique id of the step
lineIdsstring[]—Ids of the lines this step highlights
titlestring—Note card title
bodystring—Note card body; ideally a plain-language explanation of what these lines changed

The CodeChangeLineType and CodeChangeExplainerProps types are exported by name as well.

How it works

  • When lines appear and disappear: each line follows the first step that mentions it. A removed line is still there before and during that step (highlighted during it), and flows away on the next step by collapsing its height, fading out and sliding 12px to the left; an added line expands on its step. Lines no step mentions are always shown. Stepping backwards brings flowed-away removed lines back
  • Line numbers: old and new columns, as in a regular diff — removed lines only have an old number, added lines only a new one. Note card badges use the same numbers, written as ranges like −3 · +9–11
  • Syntax highlighting: a minimal built-in tokenizer with just four classes — keywords, strings, numbers and comments (double-slash and single-line block comments) — and no highlighting library
  • CSS variables: --wb-code-change-duration (default 320ms), --wb-code-change-ease (default cubic-bezier(0.22,1,0.36,1)), --wb-code-change-add (default rgb(34 197 94 / 0.12)), --wb-code-change-remove (default rgb(239 68 68 / 0.12)), plus --wb-code-change-keyword, --wb-code-change-string, --wb-code-change-number and --wb-code-change-comment for highlighting. When they are not overridden, dark mode uses brighter defaults
  • Auto-play: with autoPlay on, it advances every interval ms and loops back to the first step after the last; it pauses while the pointer is over the component and resumes when it leaves. The play button at the bottom toggles it at any time
  • Layout: the component uses a container query — when the container is wider than 36rem the note card sits to the right of the diff, otherwise it moves below

Accessibility

  • The diff is rendered as role="table"; each line is a role="row" with an aria-label that starts with "Added:" or "Removed:" for changed lines, and a leading +/− sign so highlighting does not rely on color alone
  • The note card area is aria-live="polite", so screen readers announce the new note when the step changes; the line-number badge also carries a full text description
  • Previous, Next, Auto-play and every step item are type="button" with a focus-visible ring; the current step is marked with aria-current="step" and the auto-play button reports its state with aria-pressed
  • With focus inside the component (except the diff scroll area), the left and right arrow keys go to the previous/next step; the diff scroll area is focusable with Tab and keeps arrow keys for horizontal scrolling
  • Clicking a code line to jump is a mouse shortcut; keyboard users get the same result from the step list
  • When the user has turned on reduce motion in their system settings, lines appear and disappear instantly without height or slide animation, and the note card switches without sliding