Attributes
HTML diff uses data attributes to control how elements are diffed and displayed.
data-diff-key
Required for all elements you want to track changes for.
The data-diff-key attribute provides a unique identifier that allows the diff algorithm to match elements between the "before" and "after" states.
<p data-diff-key="block-introduction">Hello World</p>
Keys should be stable and semantic: derive them from durable app data, persisted content IDs, or block identity. Avoid keys that are only based on render position, especially for ordered prose or markdown. If paragraph-2 disappears, a position-based key can cause the old second paragraph to be matched with the new second paragraph even when they are different pieces of content.
When you need to synthesize keys for content that does not already have IDs, prefer this order:
- Existing persisted IDs from your app or content model
- Stable content or block IDs generated when the content is created
- Matching unchanged siblings by text or signature
- Render position only as a last resort
Example: Adding an element
<!-- Before -->
<div>
<p data-diff-key="ixn4">First paragraph</p>
</div>
<!-- After -->
<div>
<p data-diff-key="ixn4">First paragraph</p>
<p data-diff-key="zm7q">Second paragraph</p>
</div>
Example: Removing an element
<!-- Before -->
<div>
<p data-diff-key="bw5c">Keep this</p>
<p data-diff-key="ft9x">Remove this</p>
</div>
<!-- After -->
<div>
<p data-diff-key="bw5c">Keep this</p>
</div>
data-diff-mode
Optional attribute to control diffing behavior.
By default, when text content changes, elements with data-diff-key are marked with data-diff-status="modified". The data-diff-mode attribute allows you to specify different diffing behaviors for more control.
element
Use data-diff-mode="element" to explicitly mark the element for atomic element diffing. When content changes, the old element is shown with data-diff-status="removed" and the new element is shown with data-diff-status="added".
<!-- Before -->
<div class="card" data-diff-key="my-card" data-diff-mode="element">
<h3>Old Title</h3>
<p>Old content here</p>
</div>
<!-- After -->
<div class="card" data-diff-key="my-card" data-diff-mode="element">
<h3>New Title</h3>
<p>New content here</p>
</div>
When to use element mode
✅ Use for complex HTML structures:
- Components with nested elements and specific styling
- Elements where word-level diffing would break the UI
- Cards, panels, or widgets with multiple child elements
- Interactive components (buttons, forms, etc.)
❌ Avoid for simple text content:
- Plain paragraphs or headings
- Simple text spans
- Content where word-level diffing would be more useful
words
Use data-diff-mode="words" to enable granular word-level diffing within the element instead of atomic block diffing.
Without data-diff-mode (atomic block diffing)
<!-- Before -->
<p data-diff-key="qr8n">Hello there</p>
<!-- After -->
<p data-diff-key="qr8n">Hello world</p>
With data-diff-mode="words" (granular word diffing)
<!-- Before -->
<p data-diff-key="kv3m" data-diff-mode="words">Hello there</p>
<!-- After -->
<p data-diff-key="kv3m" data-diff-mode="words">Hello world</p>
When to use data-diff-mode="words"
✅ Use for simple text content:
- Paragraphs with plain text
- Headings
- Simple spans
❌ Avoid for complex components:
- Components with nested HTML structure
- Elements with specific styling that would break with inserted spans
- Interactive components (buttons, forms, etc.)
Example: Complex component (avoid data-diff-mode="words")
This example shows how using data-diff-mode="words" on complex components breaks the layout by inserting <span> elements that disrupt the HTML structure:
<!-- ❌ DON'T: Using words mode on complex component -->
<div class="card" data-diff-key="jx9w" data-diff-mode="words">
<h3>Old Title</h3>
<p>Some content here</p>
</div>
<!-- After -->
<div class="card" data-diff-key="jx9w" data-diff-mode="words">
<h3>New Title</h3>
<p>Different content here</p>
</div>
Notice how the word-level diffing breaks the HTML structure by inserting <span> elements, making the result invalid HTML. The correct approach is to use data-diff-mode="element" or no mode at all for complex components.
data-diff-show-when-removed
Optional attribute to show removed elements in the diff result.
By default, removed elements are hidden: they are not inserted into the diff result, and only elements that still exist in the "after" HTML can receive diff attributes. Add data-diff-show-when-removed to the element in the "before" HTML when you want that removed element to be cloned into the result with data-diff-status="removed".
Minimal useful HTML for text content:
<!-- Before -->
<p
data-diff-key="block-introduction"
data-diff-mode="words"
data-diff-show-when-removed
>
The quick brown fox
</p>
<!-- After -->
<p
data-diff-key="block-introduction"
data-diff-mode="words"
data-diff-show-when-removed
>
The fast red fox
</p>
When to use data-diff-show-when-removed
✅ Use for elements safe to re-insert:
- Table rows (
<tr>) that won't break table layout
- List items (
<li>) that can be safely displayed
- Elements where showing deletions improves clarity
- Content elements that flow naturally
❌ Avoid for layout-sensitive elements:
- Elements in flexbox/grid layouts where extra DOM nodes break positioning
- Components with strict child count requirements
- Interactive elements that might cause confusion when deleted
- Elements where re-insertion might cause layout issues
Example: Table with deleted rows
<!-- Before -->
<tbody data-diff-key="table-body">
<tr data-diff-key="row1" data-diff-show-when-removed>
<td>Product A</td>
<td>$10</td>
</tr>
<tr data-diff-key="row2" data-diff-show-when-removed>
<td>Product B</td>
<td>$20</td>
</tr>
<tr data-diff-key="row3" data-diff-show-when-removed>
<td>Product C</td>
<td>$30</td>
</tr>
</tbody>
<!-- After -->
<tbody data-diff-key="table-body">
<tr data-diff-key="row1" data-diff-show-when-removed>
<td>Product A</td>
<td>$10</td>
</tr>
<tr data-diff-key="row3" data-diff-show-when-removed>
<td>Product C</td>
<td>$30</td>
</tr>
</tbody>
Notice how the removed row (Product B) is inserted and shown with strikethrough styling.
Mixed scenarios
You can be selective about which elements show when removed:
<tbody data-diff-key="table-body">
<tr data-diff-key="safe-row" data-diff-show-when-removed>
<td>This row shows when removed</td>
</tr>
<tr data-diff-key="unsafe-row">
<td>This row doesn't show when removed</td>
</tr>
</tbody>
Without data-diff-show-when-removed
Without the data-diff-show-when-removed attribute, removed elements are not inserted:
Only the existing rows are shown - the removed row is not inserted.