Diff Viewer
Code diff viewer with unified and split views, line types, gutter numbers, word-level diffs, and expandable sections.
Unified Diff
Preview
app.js
+3
-1
1
1
import express from 'express';
2
-
const port = 3000;
2
+
const port = process.env.PORT || 3000;
3
+
const host = process.env.HOST || 'localhost';
3
4
const app = express();
5
+
app.listen(port, host);
<div class="diff diff-unified">
<div class="diff-header">
<span class="diff-title">app.js</span>
<div class="diff-stats">
<span class="diff-stat-added">+3</span>
<span class="diff-stat-removed">-1</span>
</div>
</div>
<div class="diff-content">
<div class="diff-line diff-line-context">
<span class="diff-gutter">1</span>
<span class="diff-gutter">1</span>
<span class="diff-marker"> </span>
<span class="diff-code">import express from 'express';</span>
</div>
<div class="diff-line diff-line-removed">
<span class="diff-gutter">2</span>
<span class="diff-gutter"> </span>
<span class="diff-marker">-</span>
<span class="diff-code">const port = 3000;</span>
</div>
<div class="diff-line diff-line-added">
<span class="diff-gutter"> </span>
<span class="diff-gutter">2</span>
<span class="diff-marker">+</span>
<span class="diff-code">const port = process.env.PORT || 3000;</span>
</div>
<div class="diff-line diff-line-added">
<span class="diff-gutter"> </span>
<span class="diff-gutter">3</span>
<span class="diff-marker">+</span>
<span class="diff-code">const host = process.env.HOST || 'localhost';</span>
</div>
<div class="diff-line diff-line-context">
<span class="diff-gutter">3</span>
<span class="diff-gutter">4</span>
<span class="diff-marker"> </span>
<span class="diff-code">const app = express();</span>
</div>
<div class="diff-line diff-line-added">
<span class="diff-gutter"> </span>
<span class="diff-gutter">5</span>
<span class="diff-marker">+</span>
<span class="diff-code">app.listen(port, host);</span>
</div>
</div>
</div> Requires: ux.min.css
<div class="overflow-hidden font-mono text-[0.8125rem] leading-relaxed bg-base-100 border border-base-300 rounded-xl">
<div class="flex items-center justify-between px-4 py-3 bg-base-200 border-b border-base-300">
<span class="font-semibold text-sm text-base-content">app.js</span>
<div class="flex gap-3 text-xs">
<span class="text-success">+3</span>
<span class="text-error">-1</span>
</div>
</div>
<div class="overflow-x-auto">
<div class="flex bg-base-100">
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 bg-base-200 border-r border-base-300">1</span>
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 bg-base-200 border-r border-base-300">1</span>
<span class="shrink-0 w-6 text-center font-semibold select-none"> </span>
<span class="flex-1 px-4 whitespace-pre">import express from 'express';</span>
</div>
<div class="flex" style="background-color: color-mix(in oklch, var(--color-error) 10%, transparent);">
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 border-r border-base-300" style="background-color: color-mix(in oklch, var(--color-error) 15%, transparent);">2</span>
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 border-r border-base-300" style="background-color: color-mix(in oklch, var(--color-error) 15%, transparent);"> </span>
<span class="shrink-0 w-6 text-center font-semibold select-none text-error">-</span>
<span class="flex-1 px-4 whitespace-pre">const port = 3000;</span>
</div>
<div class="flex" style="background-color: color-mix(in oklch, var(--color-success) 10%, transparent);">
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 border-r border-base-300" style="background-color: color-mix(in oklch, var(--color-success) 15%, transparent);"> </span>
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 border-r border-base-300" style="background-color: color-mix(in oklch, var(--color-success) 15%, transparent);">2</span>
<span class="shrink-0 w-6 text-center font-semibold select-none text-success">+</span>
<span class="flex-1 px-4 whitespace-pre">const port = process.env.PORT || 3000;</span>
</div>
<div class="flex" style="background-color: color-mix(in oklch, var(--color-success) 10%, transparent);">
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 border-r border-base-300" style="background-color: color-mix(in oklch, var(--color-success) 15%, transparent);"> </span>
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 border-r border-base-300" style="background-color: color-mix(in oklch, var(--color-success) 15%, transparent);">3</span>
<span class="shrink-0 w-6 text-center font-semibold select-none text-success">+</span>
<span class="flex-1 px-4 whitespace-pre">const host = process.env.HOST || 'localhost';</span>
</div>
<div class="flex bg-base-100">
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 bg-base-200 border-r border-base-300">3</span>
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 bg-base-200 border-r border-base-300">4</span>
<span class="shrink-0 w-6 text-center font-semibold select-none"> </span>
<span class="flex-1 px-4 whitespace-pre">const app = express();</span>
</div>
<div class="flex" style="background-color: color-mix(in oklch, var(--color-success) 10%, transparent);">
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 border-r border-base-300" style="background-color: color-mix(in oklch, var(--color-success) 15%, transparent);"> </span>
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 border-r border-base-300" style="background-color: color-mix(in oklch, var(--color-success) 15%, transparent);">5</span>
<span class="shrink-0 w-6 text-center font-semibold select-none text-success">+</span>
<span class="flex-1 px-4 whitespace-pre">app.listen(port, host);</span>
</div>
</div>
</div> Requires: tw.min.css
// No JavaScript required for styling
// Use a diff library like 'diff' or 'jsdiff' to compute changes Split View
Preview
config.json
Original
1
{
2
"debug": false,
3
"port": 8080
4
}
Modified
1
{
2
"debug": true,
3
"port": 8080
4
}
<div class="diff diff-split">
<div class="diff-header">
<span class="diff-title">config.json</span>
<div class="diff-actions">
<button class="diff-action">Unified</button>
<button class="diff-action diff-action-active">Split</button>
</div>
</div>
<div class="diff-content">
<div class="diff-pane diff-pane-old">
<div class="diff-pane-header diff-pane-header-old">Original</div>
<div class="diff-line diff-line-context">
<span class="diff-gutter">1</span>
<span class="diff-code">{</span>
</div>
<div class="diff-line diff-line-removed">
<span class="diff-gutter">2</span>
<span class="diff-code"> "debug": false,</span>
</div>
<div class="diff-line diff-line-context">
<span class="diff-gutter">3</span>
<span class="diff-code"> "port": 8080</span>
</div>
<div class="diff-line diff-line-context">
<span class="diff-gutter">4</span>
<span class="diff-code">}</span>
</div>
</div>
<div class="diff-pane">
<div class="diff-pane-header diff-pane-header-new">Modified</div>
<div class="diff-line diff-line-context">
<span class="diff-gutter">1</span>
<span class="diff-code">{</span>
</div>
<div class="diff-line diff-line-added">
<span class="diff-gutter">2</span>
<span class="diff-code"> "debug": true,</span>
</div>
<div class="diff-line diff-line-context">
<span class="diff-gutter">3</span>
<span class="diff-code"> "port": 8080</span>
</div>
<div class="diff-line diff-line-context">
<span class="diff-gutter">4</span>
<span class="diff-code">}</span>
</div>
</div>
</div>
</div> Requires: ux.min.css
<div class="overflow-hidden font-mono text-[0.8125rem] leading-relaxed bg-base-100 border border-base-300 rounded-xl">
<div class="flex items-center justify-between px-4 py-3 bg-base-200 border-b border-base-300">
<span class="font-semibold text-sm text-base-content">config.json</span>
<div class="flex gap-2">
<button class="text-xs font-medium px-3 py-1.5 rounded border border-base-300 bg-base-100 text-base-content/60 cursor-pointer hover:bg-base-200">Unified</button>
<button class="text-xs font-medium px-3 py-1.5 rounded border border-primary bg-primary text-white cursor-pointer">Split</button>
</div>
</div>
<div class="flex overflow-x-auto">
<div class="flex-1 min-w-0 border-r border-base-300">
<div class="text-xs font-semibold px-4 py-2 text-error bg-base-200 border-b border-base-300">Original</div>
<div class="flex bg-base-100">
<span class="shrink-0 w-12 text-right pr-2 pl-2 select-none text-base-content/40 bg-base-200 border-r border-base-300">1</span>
<span class="flex-1 px-3 whitespace-pre">{</span>
</div>
<div class="flex" style="background-color: color-mix(in oklch, var(--color-error) 10%, transparent);">
<span class="shrink-0 w-12 text-right pr-2 pl-2 select-none text-base-content/40 border-r border-base-300" style="background-color: color-mix(in oklch, var(--color-error) 15%, transparent);">2</span>
<span class="flex-1 px-3 whitespace-pre"> "debug": false,</span>
</div>
<div class="flex bg-base-100">
<span class="shrink-0 w-12 text-right pr-2 pl-2 select-none text-base-content/40 bg-base-200 border-r border-base-300">3</span>
<span class="flex-1 px-3 whitespace-pre"> "port": 8080</span>
</div>
<div class="flex bg-base-100">
<span class="shrink-0 w-12 text-right pr-2 pl-2 select-none text-base-content/40 bg-base-200 border-r border-base-300">4</span>
<span class="flex-1 px-3 whitespace-pre">}</span>
</div>
</div>
<div class="flex-1 min-w-0">
<div class="text-xs font-semibold px-4 py-2 text-success bg-base-200 border-b border-base-300">Modified</div>
<div class="flex bg-base-100">
<span class="shrink-0 w-12 text-right pr-2 pl-2 select-none text-base-content/40 bg-base-200 border-r border-base-300">1</span>
<span class="flex-1 px-3 whitespace-pre">{</span>
</div>
<div class="flex" style="background-color: color-mix(in oklch, var(--color-success) 10%, transparent);">
<span class="shrink-0 w-12 text-right pr-2 pl-2 select-none text-base-content/40 border-r border-base-300" style="background-color: color-mix(in oklch, var(--color-success) 15%, transparent);">2</span>
<span class="flex-1 px-3 whitespace-pre"> "debug": true,</span>
</div>
<div class="flex bg-base-100">
<span class="shrink-0 w-12 text-right pr-2 pl-2 select-none text-base-content/40 bg-base-200 border-r border-base-300">3</span>
<span class="flex-1 px-3 whitespace-pre"> "port": 8080</span>
</div>
<div class="flex bg-base-100">
<span class="shrink-0 w-12 text-right pr-2 pl-2 select-none text-base-content/40 bg-base-200 border-r border-base-300">4</span>
<span class="flex-1 px-3 whitespace-pre">}</span>
</div>
</div>
</div>
</div> Requires: tw.min.css
// Toggle between unified and split views:
// viewer.classList.toggle('diff-unified');
// viewer.classList.toggle('diff-split'); File Status Badges
Preview
src/utils/helpers.ts
Modified
Diff content goes here...
src/new-feature.ts
Added
src/old-module.ts
Deleted
<div class="diff">
<div class="diff-file">
<svg class="diff-file-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
<span class="diff-file-name">src/utils/helpers.ts</span>
<span class="diff-file-status diff-file-status-modified">Modified</span>
</div>
<div class="diff-content" style="padding: 1rem;">
<p class="text-sm" style="color: var(--color-base-content); opacity: 0.6;">Diff content goes here...</p>
</div>
</div>
<div class="diff mt-3">
<div class="diff-file">
<svg class="diff-file-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
<span class="diff-file-name">src/new-feature.ts</span>
<span class="diff-file-status diff-file-status-added">Added</span>
</div>
</div>
<div class="diff mt-3">
<div class="diff-file">
<svg class="diff-file-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
<span class="diff-file-name">src/old-module.ts</span>
<span class="diff-file-status diff-file-status-deleted">Deleted</span>
</div>
</div> Requires: ux.min.css
<div class="overflow-hidden font-mono text-[0.8125rem] leading-relaxed bg-base-100 border border-base-300 rounded-xl">
<div class="flex items-center gap-2 px-4 py-2 bg-base-200 border-b border-base-300">
<svg class="w-4 h-4 text-base-content/60" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
<span class="font-medium text-[0.8125rem] text-base-content">src/utils/helpers.ts</span>
<span class="text-xs font-semibold uppercase px-2 py-0.5 rounded text-warning" style="background-color: color-mix(in oklch, var(--color-warning) 15%, transparent);">Modified</span>
</div>
<div class="p-4">
<p class="text-sm text-base-content/60">Diff content goes here...</p>
</div>
</div>
<div class="overflow-hidden font-mono text-[0.8125rem] leading-relaxed bg-base-100 border border-base-300 rounded-xl mt-3">
<div class="flex items-center gap-2 px-4 py-2 bg-base-200 border-b border-base-300">
<svg class="w-4 h-4 text-base-content/60" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
<span class="font-medium text-[0.8125rem] text-base-content">src/new-feature.ts</span>
<span class="text-xs font-semibold uppercase px-2 py-0.5 rounded text-success" style="background-color: color-mix(in oklch, var(--color-success) 15%, transparent);">Added</span>
</div>
</div>
<div class="overflow-hidden font-mono text-[0.8125rem] leading-relaxed bg-base-100 border border-base-300 rounded-xl mt-3">
<div class="flex items-center gap-2 px-4 py-2 bg-base-200 border-b border-base-300">
<svg class="w-4 h-4 text-base-content/60" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
<span class="font-medium text-[0.8125rem] text-base-content">src/old-module.ts</span>
<span class="text-xs font-semibold uppercase px-2 py-0.5 rounded text-error" style="background-color: color-mix(in oklch, var(--color-error) 15%, transparent);">Deleted</span>
</div>
</div> Requires: tw.min.css
// No JavaScript required Word Diff & Highlights
Preview
Inline word changes
5
-
const message = "Hello World";
5
+
const message = "Hello, World!";
<div class="diff diff-unified diff-word">
<div class="diff-header">
<span class="diff-title">Inline word changes</span>
</div>
<div class="diff-content">
<div class="diff-line diff-line-removed">
<span class="diff-gutter">5</span>
<span class="diff-gutter"> </span>
<span class="diff-marker">-</span>
<span class="diff-code">const message = <span class="diff-highlight-removed">"Hello World"</span>;</span>
</div>
<div class="diff-line diff-line-added">
<span class="diff-gutter"> </span>
<span class="diff-gutter">5</span>
<span class="diff-marker">+</span>
<span class="diff-code">const message = <span class="diff-highlight-added">"Hello, World!"</span>;</span>
</div>
</div>
</div> Requires: ux.min.css
<div class="overflow-hidden font-mono text-[0.8125rem] leading-relaxed bg-base-100 border border-base-300 rounded-xl">
<div class="flex items-center justify-between px-4 py-3 bg-base-200 border-b border-base-300">
<span class="font-semibold text-sm text-base-content">Inline word changes</span>
</div>
<div class="overflow-x-auto">
<div class="flex" style="background-color: color-mix(in oklch, var(--color-error) 10%, transparent);">
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 border-r border-base-300" style="background-color: color-mix(in oklch, var(--color-error) 15%, transparent);">5</span>
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 border-r border-base-300" style="background-color: color-mix(in oklch, var(--color-error) 15%, transparent);"> </span>
<span class="shrink-0 w-6 text-center font-semibold select-none text-error">-</span>
<span class="flex-1 px-4 whitespace-pre">const message = <span class="rounded-sm px-0.5" style="background-color: color-mix(in oklch, var(--color-error) 30%, transparent);">"Hello World"</span>;</span>
</div>
<div class="flex" style="background-color: color-mix(in oklch, var(--color-success) 10%, transparent);">
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 border-r border-base-300" style="background-color: color-mix(in oklch, var(--color-success) 15%, transparent);"> </span>
<span class="shrink-0 w-14 text-right pr-2 pl-2 select-none text-base-content/40 border-r border-base-300" style="background-color: color-mix(in oklch, var(--color-success) 15%, transparent);">5</span>
<span class="shrink-0 w-6 text-center font-semibold select-none text-success">+</span>
<span class="flex-1 px-4 whitespace-pre">const message = <span class="rounded-sm px-0.5" style="background-color: color-mix(in oklch, var(--color-success) 30%, transparent);">"Hello, World!"</span>;</span>
</div>
</div>
</div> Requires: tw.min.css
// Use a word-diff algorithm to compute inline changes