Data Display
DiffViewer
A diff, unified or side by side, with the syntax colouring the rest of the library uses.
import { DiffViewer } from 'omaris' Examples
Basic
Give it before and after. A second diff runs inside a changed pair of lines, so a renamed variable shows as one word moving rather than two whole lines replaced.
<script lang="ts"> import { DiffViewer } from 'omaris'; const before = `export function total(items) { let sum = 0; for (const item of items) { sum += item.price; } return sum;}`; const after = `export function total(items, tax = 0) { let sum = 0; for (const item of items) { sum += item.price * item.qty; } return sum * (1 + tax);}`;</script><DiffViewer {before} {after} lang="ts" title="total.ts" class="w-full" /> Split and context
switchable offers the unified / split toggle, and view is bindable so the choice is yours to keep. context is how many unchanged lines survive either side of a change — the rest collapse into a strip you can click open.
<script lang="ts"> import { DiffViewer, Text, type DiffView } from 'omaris'; const before = `// boilerplate line 1// boilerplate line 2// boilerplate line 3// boilerplate line 4const theme = 'light';const radius = 8;// trailing line 1// trailing line 2// trailing line 3// trailing line 4`; const after = `// boilerplate line 1// boilerplate line 2// boilerplate line 3// boilerplate line 4const theme = 'system';const radius = 12;const easing = 'emphasized';// trailing line 1// trailing line 2// trailing line 3// trailing line 4`; let view = $state<DiffView>('split');</script><div class="flex w-full flex-col gap-2"> <DiffViewer {before} {after} lang="ts" bind:view switchable context={1} titles={['tokens.ts (main)', 'tokens.ts (branch)']} height="20rem" /> <Text variant="label-sm" tone="muted">view: {view}</Text></div> From a patch
Hand it the patch that git diff printed and it renders that instead — identically, since both end up in the same shape. wrap keeps long lines on screen, and classes.viewport replaces the height the property sets.
<script lang="ts"> import { DiffViewer } from 'omaris'; const patch = `diff --git a/src/lib/utils.ts b/src/lib/utils.ts--- a/src/lib/utils.ts+++ b/src/lib/utils.ts@@ -1,7 +1,8 @@ import { clsx, type ClassValue } from 'clsx';-import { twMerge } from 'tailwind-merge';+import { extendTailwindMerge } from 'tailwind-merge';++const twMerge = extendTailwindMerge({ extend: { classGroups: { shadow: ['shadow-1'] } } }); export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); }`;</script><DiffViewer {patch} lang="ts" size="sm" wrap view="unified" height="auto" classes={{ viewport: 'max-h-64', header: 'bg-surface-container-low' }} class="w-full"/> When to use it
Use it for
- Two versions of a file or setting: a review, an audit trail, what changed since the last publish. Pass
beforeandafter. A renamed variable shows as one word moving, not two lines replaced. - A patch from a server or
git diff.patchrenders it as is, with nobefore/afterto reconstruct. - A long file with one change.
context={3}keeps three lines either side and folds the rest into a strip that opens on click. - Side by side on a wide screen.
view="split", plusswitchableto let the reader choose.viewis bindable, so the choice can be kept.
Not for
- A hand-written five-line change in a docs page → Code Block with
diff. - Reviewing and fixing the change → Code Editor beside it. The viewer is read-only.
- Two JSON documents → JSON Viewer to explore one. For the difference, pretty-print both with the same key order and pass them here as
lang="json". - Prose that changed. A line diff of a paragraph is one changed line. Diff at the word level in the editor that owns the prose.
Do
- Set
lang. Both sides are highlighted whole, so a block comment or a multi-line string stays coloured across a change. - Name the file with
title, ortitles={['old.ts', 'new.ts']}for a rename. Keepstatsso+12 −4says how big the change is. - Cap it with
heightin a sheet or card. Usewrapin a narrow column instead of sideways scrolling. - Set
emptyTextfor "nothing changed". A blank frame reads as broken.
Don't
- Pass
context={Infinity}for a long file. 400 unchanged lines are not the change. - Force
spliton a phone. Unified is the one that fits. - Re-tint the rows by hand. The three change colours are slots shared by both views.
Quick reference
size smmd(default)
API
DiffViewer
A diff, unified or side by side, with the syntax colouring the rest of the library uses.
Two things separate this from a red-and-green list of lines. It runs a second diff inside a changed pair of lines, so a renamed variable shows as one word moving rather than two whole lines replaced; and long runs of untouched code collapse to a strip you can click, because the point of a diff is what changed and 400 unchanged lines are not it.
Feed it before and after and it does the work, or hand it the patch that git diff printed and it will render that instead — identically, since both end up in the same shape.
import { DiffViewer } from 'omaris' <DiffViewer lang="ts" {before} {after} view="split" context={3} /> Parts
Every element this renders is reachable from outside. Pass Tailwind for one part as classes={{ part: '…' }}; class covers the root and is merged last, so it always wins.
root- No description in the source yet.
header- Filename, stats, and the view switch.
title- No description in the source yet.
stats+12 −4.added- No description in the source yet.
removed- No description in the source yet.
action- No description in the source yet.
viewport- The scroll container.
table- Everything inside the scroller, sized to the widest line.
row- One line, or one pair of lines in split view.
side- Half a split row.
gutter- A line number, pinned against horizontal scroll.
sign- The
+/−column. code- The code itself.
word- A run of characters added or removed inside a changed line.
gap- The "N unchanged lines" strip.
empty- Shown when the two sides are the same.
Props
before Defaults to ''
string The old text. Ignored when patch is given.
after Defaults to ''
string The new text.
patch string A unified patch, as git diff prints it. Wins over before/after.
lang Defaults to 'plain'
string ts, svelte, css, … — the same names CodeBlock takes.
view bindableDefaults to 'unified'
DiffView size Defaults to 'md'
DiffViewerSize smmd
context Defaults to 3
number Unchanged lines kept either side of a change. Infinity keeps them all.
lineNumbers Defaults to true
boolean wrap Defaults to false
boolean title string Filename in the header.
titles [string, string] Per-side filenames, for a rename. Falls back to title.
stats Defaults to true
boolean Show the +n −n counts.
switchable Defaults to false
boolean Offer the unified / split switch.
emptyText Defaults to 'No changes.'
string Shown when nothing changed.
height Defaults to '32rem'
number | string Tallest the scroller gets. A number is px, a string any CSS length.
class string classes DiffViewerClasses