DiffViewer
<DiffViewer> shows what changed between two versions. One primitive, two render paths via kind="text" | "json". Used for audit trails, version compare, workflow inbox, configuration review.
When to use
- Audit log entries that need to surface “what changed” inline.
- Version-history compare (workflow YAML, prompt edits, agent config).
- Approval flows where the reviewer needs to see the delta from baseline.
Don’t use DiffViewer for: image / PDF diff (out of scope), real-time collaborative editing (use a CRDT-aware editor), or showing absolute values when the user doesn’t care about the change (just render the after-version).
Text mode
Line-level diff. Default mode. Whitespace and indentation are preserved.
Before
After
name: marketing-bot
prompt: |
You are a friendly outbound campaign assistant.
Removed: Aim for 3 turns max.
Added: Aim for 5 turns and follow up with an email.
tools:
- search_kb
Removed: - book_meeting
Added: - book_meeting
Added: - send_email
<DiffViewer kind="text" before={oldYaml} after={newYaml} />Hide unchanged sections
For long files where most content is unchanged, set hideUnchanged and tune contextLines (default 3) for how much surrounding context to keep around each hunk.
Before
After
prompt: |
You are a friendly outbound campaign assistant.
Removed: Aim for 3 turns max.
Added: Aim for 5 turns and follow up with an email.
tools:
- search_kb
Removed: - book_meeting
Added: - book_meeting
Added: - send_email
<DiffViewer kind="text" before={oldYaml} after={newYaml} hideUnchanged contextLines={2}/>JSON mode
Pass JS values directly — DiffViewer pretty-prints both sides and renders a key-aware structural diff.
Before
After
{
"name": "Acme Corp",
Removed: "stage": "Discovery",
Removed: "amount": 24000,
Added: "stage": "Negotiation",
Added: "amount": 32000,
"tags": [
"priority",
"enterprise",
Added: "flagged"
],
Removed: "owner": "alice"
Added: "owner": "bob"
}
<DiffViewer kind="json" before={{ stage: 'Discovery', amount: 24000 }} after={{ stage: 'Negotiation', amount: 32000 }}/>API
| Prop | Type | Default | Description |
|---|---|---|---|
kind | "text" | "json" | "text" | Render mode. JSON pretty-prints both sides and runs a structural diff. |
before * | string | unknown | — | Previous version. String for kind="text"; any value for kind="json". |
after * | string | unknown | — | New version. |
hideUnchanged | boolean | false | Collapse long context regions between changed hunks. |
contextLines | number | 3 | Lines kept around each hunk when hideUnchanged is true. |
beforeLabel | ReactNode | "Before" | Header label for the before column. |
afterLabel | ReactNode | "After" | Header label for the after column. |
className | string | — | Forwarded to the wrapper. |
Design guidelines
✓ Do
- Use kind="json" for any structured value (objects, arrays, configurations). Stringifying first then text-diffing produces noisier output.
- Set hideUnchanged when the diff is small relative to total content. The reviewer needs to find the delta, not scroll past unchanged lines.
- Keep beforeLabel / afterLabel concise and informative — "v3" / "v4", "Baseline" / "Proposed", not file hashes.
✗ Don't
- Use DiffViewer for showing the after-version when nothing of importance changed. Just render the after-version.
- Wrap DiffViewer in a tooltip or popover. The diff is information-dense; it needs space.
- Collapse with contextLines=0. Diffs without any context are hostile — the reader can't tell what changed.
Accessibility
- Added rows render with a visually-hidden
"Added: "prefix; removed rows with"Removed: ". Color is never the only signal. - Line numbers and the
+/−sign arearia-hiddenbecause the prefix conveys the same meaning. - The collapsed-section marker (
⋯) isaria-hidden— surrounding kept rows carry the structural meaning.