Skip to content
usefy

DiffViewer

ComponentsText diffing

Text diff viewer for React — hand-written linear-space Myers engine, word-level highlighting, collapsible context, row virtualization, and a zero-dependency headless core

Live demo

Install

$ npm install @usefy/diff-viewer

Quick start

DiffViewer.tsx
import { DiffViewer } from "@usefy/diff-viewer";

function Review({ before, after }: { before: string; after: string }) {
  return <DiffViewer oldText={before} newText={after} view="split" />;
}

API reference

<DiffViewer />

<DiffViewer
  oldText={before}                 // the "before" document
  newText={after}                  // the "after" document
  view="split"                     // "split" | "unified"
  showLineNumbers                  // default true
  wrap={false}                     // wrap long lines (disables virtualization)
  theme="system"                   // "light" | "dark" | "system"
  context={3}                      // unchanged lines around each change (Infinity = whole file)
  ignoreWhitespace="none"          // "none" | "trailing" | "all" — matching only
  ignoreCase={false}               // matching only; renders the original
  inlineThreshold={0.5}            // min similarity to word-diff a changed pair
  maxEditDistance={6000}           // cost guard — refuse "too different" pairs
  virtualizeThreshold={200}        // window the DOM above this row count
  diff={precomputed}               // optional: a DiffResult, skips computeDiff
  renderContent={({ text }) => ...} // the syntax-highlighting seam
  labels={{ noChanges: "…" }}      // every string overridable for i18n
  classNames={{ root: "…" }}       // per-slot class names
  onExpand={(hunkIndex, lines) => {}}
/>

See the full options table. All numeric options are NaN/Infinity-guarded.

computeDiff(oldText, newText, options?)

The headless engine — two strings in, a DiffResult out:

interface DiffResult {
  hunks: DiffHunk[];                          // the renderable regions
  stats: { added: number; removed: number; unchanged: number };
  truncated: boolean;                         // a guard refused the diff
  truncatedReason?: "size" | "complexity";    // too big vs. too different
  inlineBudgetExhausted?: true;               // some word-highlighting was skipped
}

Each DiffHunk carries its collapsed lines (hiddenBefore / hiddenAfter as real DiffLine[]), so a pre-computed diff prop can expand with no source texts. See headless usage.


Go deeper

This page is the quick reference. For every example, prop, and edge case, read the full README — or open Storybook to change props live.

More in components