Welcome to Vanilla Breeze
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
When to use
There's no <diff-viewer> in VB — by design. The "diff" use case fans out into five very different shapes, each handled by an existing primitive (or a small composition). Pick the one that matches the shape of your diff, not the word "diff".
| Use case | Reach for |
|---|---|
Author-marked-up inline change tracking (<ins> / <del> in prose) |
<change-set> |
| Side-by-side image before-after with a draggable handle | <compare-surface> |
| Editorial review surface with comments and pinned annotations | <review-surface> |
| Switch between page versions; show the diff between them | <version-switcher data-action="diff"> |
| Compute a runtime text diff yourself and render it through tracking-view UI | text-diff utility → mount inside <change-set> |
<diff-viewer>?"Diff display" is a shape, not a primitive. The five rows above all show "what changed," but they have wildly different inputs (authored markup vs computed strings vs image pairs vs comment trees), interaction models (toggle view vs drag a handle vs pin a comment), and lifecycle (static vs runtime fetch). Bundling them into a single <diff-viewer> would either:
<change-set> / <compare-surface> / <review-surface> already do well, fragmenting the codebase.This follows the May 2026 Planning consolidation pattern (decision-matrix, swot-analysis, stakeholder-map, retrospective-board all became recipes on existing primitives instead of new components). Same call here.
<change-set>When the diff is part of your authored content (a release note showing what's been deprecated, an editorial change with rationale), wrap the <ins> / <del> markup in <change-set>. Readers get a tracking / final / original view toggle for free.
<change-set datetime="2026-02-20" author="tpowell"> <p> Send requests to <del>/api/v1/upload</del> <ins>/api/v2/ingest</ins> with a <del>Content-Type: application/xml</del> <ins>Content-Type: application/json</ins> header. </p></change-set>
<compare-surface>Two images stacked with a draggable wipe handle. Use this for visual diffs (design iterations, screenshot comparisons, before/after photos).
<compare-surface> <img slot="before" src="/screens/v1.png" alt="v1 layout"> <img slot="after" src="/screens/v2.png" alt="v2 layout"></compare-surface>
<review-surface>When the diff carries conversation (comments pinned to the changes, suggestions, accept/reject flows), use <review-surface>. It composes <change-set> for the inline marks and adds the pin / comment / status machinery on top.
See the <review-surface> reference for the full slot / event shape.
<version-switcher>If you've already declared the page's versions (release versions or per-page edit history) for a <version-switcher>, the diff action gives you a one-line setup: pick a version from the picker, the component fetches it, computes the line-level diff against the current page's versioned region, and mounts a <change-set> with the diff inline.
<version-switcher data-action="diff" data-versions='[ {"id":"v2.1","label":"v2.1","url":"/v2.1/api","current":true}, {"id":"v2.0","label":"v2.0","url":"/v2/api"}, {"id":"v1.4","label":"v1.4","url":"/v1.4/api","archived":true}]'></version-switcher> <main data-versioned> <h1>API documentation</h1> …</main>
This is the highest-level recipe — almost no wiring required. Use it whenever the diff is "between this page now and that page archived."
text-diff utilityIf your inputs aren't whole pages (e.g., comparing two API response bodies, two user-submitted strings, two arbitrary text snippets), import the text-diff utility directly and mount the result inside a <change-set> for the tracking-view chrome.
import { diffLines, renderDiffFragment } from '/src/utils/text-diff.js';// Make sure change-set is registered (autoload bundle covers this). function mountDiff(host, oldText, newText) { const ops = diffLines(oldText, newText); const cs = document.createElement('change-set'); cs.appendChild(renderDiffFragment(ops)); host.replaceChildren(cs); // change-set renders tracking / final / original view toggle for free.}
The utility ships line-level LCS diff — good enough up to the low thousands of lines. For markup-aware diff, post-process the ops yourself or compose with a dedicated diff library.
diffLines(oldText, newText) returns an array of operations:
<code>renderDiffFragment(ops)</code> wraps those ops into a <code><pre class="text-diff">…</pre></code> with <code><ins></code> / <code><del></code> runs — the markup that <code><change-set></code> understands for its tracking-view toggle.<p></p>
Compose the text-diff utility into two parallel columns yourself with <layout-grid> — one column showing only the additions, one showing only the deletions. Or use <change-set>'s "final" + "original" view toggle for the same effect without the layout work.
Side-by-side as a default rendering is rarely worth the horizontal real estate cost; tracking-view (interleaved with toggle) reads better in narrow contexts. If you find a real use case, file a bead with the screenshots / requirements.