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"));

Before

|

After

|

Diff Result

|

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;
}

Before

|

After

|

Diff Result

|

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:

Before

|

After

|

Diff Result

|

Notice how data-diff-mode="words" enables word-level highlighting instead of highlighting the entire element. Learn more in the attributes guide.