Getting Started
Overview
HTML Diff is a simple way to generate and display diffs for any app UI.
Assume you want to diff a table that's displayed to users. You render the before and after HTML, then pass both into the renderHtmlDiff function to get the diff:
import { renderHtmlDiff } from "@lix-js/html-diff";
const tableBefore = renderTable(beforeData);
const tableAfter = renderTable(afterData);
const diff = renderHtmlDiff({
beforeHtml: tableBefore,
afterHtml: tableAfter,
// Optional: configure which attribute is used to match elements
// diffAttribute: 'data-id',
});
render(diff, document.getElementById("diff-container"));
Notice how the rendered diff automatically highlights changed cells while preserving the table structure. This works without any custom diff logic - just your existing HTML with data-diff-key attributes.
- 🌐 Universal: Works for any app that renders to HTML (which is most apps!)
- ⚡ Simple: No need for renderer-specific diff logic.
- 🎨 Uses your styles: Uses your existing CSS.
- 🔧 Framework Agnostic: Works with React, Vue, Svelte, Angular, and more.
Installation
npm install @lix-js/html-diff
Usage
Quickstart
import { renderHtmlDiff } from "@lix-js/html-diff";
import "@lix-js/html-diff/default.css";
const beforeHtml = `<p data-diff-key="x9n4" class="my-text">The quick brown fox</p>`;
const afterHtml = `<p data-diff-key="x9n4" class="my-text">The fast red fox</p>`;
const diff = renderHtmlDiff({ beforeHtml, afterHtml });
// Vanilla
document.getElementById("diff-container")!.innerHTML = diff;
// React
function Diff({ html }: { html: string }) {
return <div dangerouslySetInnerHTML={{ __html: html }} />;
}
Include the default styling if you want ready-made highlights:
import "@lix-js/html-diff/default.css";
Step 1: Adddata-diff-key attributes
Add unique data-diff-key attributes to elements you want to track for changes. Use random, short identifiers (not semantic names):
<!-- ✅ Good: Random keys -->
<div data-diff-key="k7m2">User content</div>
<p data-diff-key="x9n4">Some text</p>
<!-- ❌ Avoid: Semantic names -->
<div data-diff-key="user-profile">...</div>
<p data-diff-key="description">...</p>
Key guidelines:
- Use the same key for the same element in before/after HTML
- Only add keys to elements you want to diff (not every element)
- Elements without keys remain unchanged in the diff
Programmatic key generation
In most apps you will programatically generate the keys based on your data:
function UserCard({ user }) {
return (
<div>
<h3 data-diff-key={`user-${user.id}-name`}>{user.name}</h3>
<p data-diff-key={`user-${user.id}-email`}>{user.email}</p>
</div>
);
}
// Same component with different data = matching keys for diffing
const beforeHtml = renderToString(<UserCard user={oldUser} />);
const afterHtml = renderToString(<UserCard user={newUser} />);
Step 2: Generate the diff
Use renderHtmlDiff to compare your before and after HTML:
import { renderHtmlDiff } from "@lix-js/html-diff";
const beforeHtml = `<p data-diff-key="x9n4">The quick brown fox</p>`;
const afterHtml = `
<p data-diff-key="x9n4">The fast red fox</p>
<p data-diff-key="k7m2">The lazy dog sleeps</p>
`;
const diff = renderHtmlDiff({ beforeHtml, afterHtml });
// The diff now contains:
// - "The fast red fox" with data-diff-status="modified"
// - "The lazy dog sleeps" with data-diff-status="added"
Step 3: Render the diff
The diff HTML preserves your original elements and styling—only data-diff-status attributes are added. Your app's existing CSS continues to work:
// Vanilla JS
document.getElementById("diff-container")!.innerHTML = diff;
// React
function DiffViewer({ diff }: { diff: string }) {
return <div dangerouslySetInnerHTML={{ __html: diff }} />;
}
/* Your existing app styles */
.my-text {
font-size: 24px;
font-weight: bold;
color: #2d3748;
font-family: Georgia, serif;
line-height: 1.4;
}
/* Only these selectors needed for diff highlighting */
[data-diff-status="added"] {
color: #22c55e;
}
[data-diff-status="modified"] {
color: #f59e0b;
}
[data-diff-status="removed"] {
color: #ef4444;
}
Notice how your existing .my-text styles (large, bold typography) are preserved. Only the diff highlighting is added on top based on your CSS targeting data-diff-status.
Step 4: Make diffs more granular (optional)
For word-level highlighting within text elements, add the data-diff-mode="words" attribute:
Notice how data-diff-mode="words" enables word-level highlighting instead of highlighting the entire element. Learn more in the attributes guide.