Most Diff UIs Are Just Colored Spans. That Is Not a Diff.
TLDR
Token-based inline diff wrappers (e.g.jsdiff wrapping added/removed text in inline <span> tags) fail for document-level side-by-side comparison interfaces because token streams do not preserve line number alignment or vertical row correspondence. Building a true line-by-line diff engine requires a two-pass architecture: Pass 1 executes line-array diffing (diffArrays), while Pass 2 pairs removed and added line blocks 1-to-1 into aligned row objects.
| Diff Implementation | Line Number Alignment | Vertical Pane Sync | Ideal Use Case |
|---|---|---|---|
| Token-Based Inline Spans | Fails (Tokens break line alignment) | Fails (Panes drift vertically) | Short inline text fields |
| Line-Oriented Row Pairing | 100% (Line-for-line alignment) | 100% (Synchronized row heights) | Multi-page document comparison |
Technical implementation: two-pass line pairing algorithm
// Two-Pass Line Diff Engine: Pair removed and added lines 1-to-1 for side-by-side alignment
export function buildLineAlignedDiffPairs(lineDiffResults) {
const alignedRows = [];
for (const part of lineDiffResults) { if (!part.added && !part.removed) { // Unchanged lines: Pair identical left and right lines for (const line of part.value) { alignedRows.push({ left: line, right: line, type: 'equal' }); } } else if (part.removed) { // Buffer removed lines block alignedRows.push({ _removedLines: part.value }); } else if (part.added) { const prevBlock = alignedRows[alignedRows.length - 1];
if (prevBlock?._removedLines) { // Pair removed and added blocks 1-to-1 by index const removed = prevBlock._removedLines; const added = part.value; alignedRows.pop(); // Remove buffered block
const maxLen = Math.max(removed.length, added.length); for (let i = 0; i < maxLen; i++) { alignedRows.push({ left: i < removed.length ? removed[i] : null, right: i < added.length ? added[i] : null, type: i < removed.length && i < added.length ? 'change' : (i < removed.length ? 'remove' : 'add') }); } } else { for (const line of part.value) { alignedRows.push({ left: null, right: line, type: 'add' }); } } } }
return alignedRows; }
Rule of thumb: Execute line-array diffing and 1-to-1 row pairing before running inline token diffing on modified document lines.