# @humanspeak/svelte-diff — full reference
> Concatenated dump of every doc page under https://diff.svelte.page/docs.
> Each section is bounded by an HTML comment with the source URL,
> so agents can extract individual pages or cite a specific section.
---
## Install
```bash
npm install @humanspeak/svelte-diff
```
`@humanspeak/svelte-diff` is the Svelte 5 component package. It accepts `originalText` and `modifiedText`, computes a diff reactively, and renders removed, inserted, equal, and expected segments.
Use this library when the desired result is a rendered text diff inside a Svelte application. Use a lower-level algorithm library when you need patch creation, patch application, non-UI diff data, or non-Svelte runtimes.
## Minimal example
```svelte
```
## Important behavior
- `cleanupSemantic` improves readability and takes precedence over efficiency cleanup.
- `cleanupEfficiency` defaults to `4`; set it to `0` to skip efficiency cleanup.
- Expected patterns use named capture groups such as `(?\\d{4})` inside `originalText`.
- Child snippets override the corresponding `renderers` entry, which overrides built-in markup.
- `onProcessing` receives timing, raw diff tuples, and optional expected-pattern captures.
---
# SvelteDiff API
> Complete SvelteDiff component API including props, renderer precedence, callbacks, and defaults.
**Source:** [https://diff.svelte.page/docs/api/svelte-diff](https://diff.svelte.page/docs/api/svelte-diff)
---
The package exports the component as both the default export and a named export.
```svelte
```
## Props
| Prop | Type | Default | Purpose |
|---|---|---:|---|
| `originalText` | `string` | required | The before/source text |
| `modifiedText` | `string` | required | The after/target text |
| `timeout` | `number` | `1` | Maximum diff computation time in seconds; `0` is unlimited |
| `cleanupSemantic` | `boolean` | `false` | Optimize edit boundaries for human readability |
| `cleanupEfficiency` | `number` | `4` | Edit cost used by efficiency cleanup; `0` disables it |
| `compact` | `boolean` | `true` | Render unstyled equal text without wrapper spans; `false` restores legacy equal spans |
| `onProcessing` | `function` | — | Receive timing, raw tuples, and optional captures |
| `rendererClasses` | `RendererClasses` | `{}` | Classes for built-in segment spans |
| `renderers` | `Partial` | `{}` | Snippet map for individual segment types |
| `remove` | `Snippet<[string]>` | — | Direct child snippet for removed text |
| `insert` | `Snippet<[string]>` | — | Direct child snippet for inserted text |
| `equal` | `Snippet<[string]>` | — | Direct child snippet for unchanged text |
| `expected` | `Snippet<[string, string]>` | — | Direct child snippet for expected values |
| `lineBreak` | `Snippet<[]>` | — | Direct child snippet between lines |
## Cleanup precedence
The component computes a raw diff, then runs at most one cleanup pass:
1. If `cleanupSemantic` is `true`, semantic cleanup runs.
2. Otherwise, if `cleanupEfficiency > 0`, efficiency cleanup runs with that value as the edit cost.
3. Otherwise, the raw diff is rendered.
## Renderer precedence
Resolution happens independently for every segment type:
1. A direct child snippet such as `{#snippet insert(text)}`
2. The matching property in `renderers`
3. The built-in fallback
For unchanged text, the default compact fallback emits text directly when no equal class or
renderer is configured. Set `compact={false}` to restore the legacy equal ``. Removed,
inserted, expected, and customized equal segments retain their normal elements.
That means you can override one type and leave all others on their defaults.
```svelte
{#snippet insert(text: string)}
+ {text}
{/snippet}
```
## `onProcessing`
The callback runs after computation and cleanup.
```svelte
```
Timing values are milliseconds measured with `performance.now()`.
## Expected patterns
If `originalText` contains named capture groups, the component tries to match those regions in `modifiedText` and renders successful matches as `expected` instead of additions/removals.
```svelte
v\\d+\\.\\d+\\.\\d+)'}
modifiedText="Release v2.4.1"
/>
```
The group name is passed to the expected snippet and its matched value appears in the callback's `captures` object.
## Deprecated aliases
`SvelteDiffMatchPatch` and the `SvelteDiffMatchPatch*` type names remain available for compatibility. New code should use `SvelteDiff` and the shorter `SvelteDiff*` types.
# Types and Exports
> Public components, callbacks, renderer maps, tuples, and expected-pattern types exported by @humanspeak/svelte-diff.
**Source:** [https://diff.svelte.page/docs/api/types](https://diff.svelte.page/docs/api/types)
---
# Types & Exports
Everything public is exported from the package root.
```typescript
import SvelteDiff, {
SvelteDiff as NamedSvelteDiff,
type SvelteDiffProps,
type SvelteDiffTiming,
type SvelteDiffTuple,
type Renderers,
type RendererClasses,
type CaptureRange,
type DisplayDiff,
type PatternMatchResult
} from '@humanspeak/svelte-diff'
```
## Components
| Export | Notes |
|---|---|
| `default` | The `SvelteDiff` component |
| `SvelteDiff` | Named export of the same component |
| `SvelteDiffMatchPatch` | Deprecated compatibility alias |
## `SvelteDiffTiming`
```typescript
type SvelteDiffTiming = {
main: number
cleanup: number
total: number
}
```
All values are milliseconds. `main` measures the core algorithm, `cleanup` measures the selected cleanup pass, and `total` covers both.
## `SvelteDiffTuple`
An alias for `Diff` from `diff-match-patch-ts`. Each tuple is an operation and its text:
```typescript
type SvelteDiffTuple = [operation: -1 | 0 | 1, text: string]
```
- `-1` — removed
- `0` — equal
- `1` — inserted
## `Renderers`
```typescript
type Renderers = {
remove?: Snippet<[string]>
equal?: Snippet<[string]>
insert?: Snippet<[string]>
expected?: Snippet<[string, string]>
lineBreak?: Snippet<[]>
}
```
The expected renderer receives both the matched text and its named capture-group name.
## `RendererClasses`
```typescript
type RendererClasses = {
remove?: string
equal?: string
insert?: string
expected?: string
}
```
Classes only affect built-in fallbacks. When you replace a segment with a snippet, that snippet owns its own classes.
## Expected-pattern types
`CaptureRange` describes a named match inside the modified string. `DisplayDiff` is an internal-rendering-shaped segment that may carry an `expected` group name. `PatternMatchResult` combines resolved template text, captured values, and capture ranges.
```typescript
interface PatternMatchResult {
resolvedText: string
captures: Record
captureRanges: CaptureRange[]
}
```
These are exported for integrations that want to share the component's expected-region concepts without duplicating type definitions.
# Getting Started
> Install @humanspeak/svelte-diff and render a readable, reactive text diff in Svelte 5.
**Source:** [https://diff.svelte.page/docs/getting-started](https://diff.svelte.page/docs/getting-started)
---
`@humanspeak/svelte-diff` is a focused Svelte 5 component for comparing two strings. It runs the diff-match-patch algorithm, optionally cleans the result for readability, and renders each change as real Svelte markup.
## Installation
```bash
npm install @humanspeak/svelte-diff
```
```bash
pnpm add @humanspeak/svelte-diff
```
## Your first diff
```svelte
```
By default, removed text is red with a strike-through, inserted text is green, and unchanged text
is unstyled. Unstyled unchanged text uses compact DOM without wrapper spans; pass
`compact={false}` when migrating selectors or styles that require the legacy equal spans. Text is
escaped by Svelte; the component does not inject an HTML string.
## Reactive inputs
Both required props are reactive. If either string changes, the component recomputes the diff.
```svelte
```
## Recommended readable defaults
For prose and user-facing copy, semantic cleanup is usually the best starting point:
```svelte
```
For machine-like strings where every small edit matters, keep semantic cleanup off and use the default efficiency cleanup.
## Styling with classes
Use `rendererClasses` when you want to keep the default `` markup:
```svelte
```
Use child snippets when you need different elements, attributes, icons, or animation. See [Custom Rendering](/docs/guides/custom-rendering).
## Next steps
- [SvelteDiff API](/docs/api/svelte-diff) — every prop and precedence rule
- [Expected Patterns](/docs/guides/expected-patterns) — separate intentional variation from real changes
- [Cleanup Modes](/docs/guides/cleanup) — choose semantic, efficiency, or raw output
- [Interactive Examples](/examples) — edit values and inspect real output
- [Comparisons](/compare) — decide between this component and lower-level diff tools
# Cleanup Modes
> Choose semantic cleanup, efficiency cleanup, or raw diff output for the right balance of readability and fidelity.
**Source:** [https://diff.svelte.page/docs/guides/cleanup](https://diff.svelte.page/docs/guides/cleanup)
---
The core algorithm finds a valid sequence of edits. Cleanup passes reorganize that sequence without changing the final text.
## Semantic cleanup
```svelte
```
Semantic cleanup shifts edit boundaries toward natural-looking word and phrase boundaries. Use it for prose, review screens, changelogs, and other output read by people.
It may produce a slightly larger edit than the mathematically smallest diff if that edit is easier to understand.
## Efficiency cleanup
```svelte
```
Efficiency cleanup removes operationally trivial equalities. The number becomes the algorithm's edit-cost setting. `4` is the component default.
Higher values make small equal regions more likely to be absorbed into surrounding edits. Lower values preserve more fine-grained equalities.
## Raw output
Disable both cleanup paths when exact algorithm output matters:
```svelte
```
## Precedence
Semantic cleanup wins when enabled. The component does not run semantic and efficiency cleanup in sequence.
| Configuration | Cleanup pass |
|---|---|
| `cleanupSemantic={true}` | semantic |
| `cleanupSemantic={false}`, `cleanupEfficiency={4}` | efficiency |
| `cleanupSemantic={false}`, `cleanupEfficiency={0}` | none |
## Choosing a mode
- Use **semantic** for prose and human review.
- Use **efficiency** for compact technical diffs and a balanced default.
- Use **raw** when consuming the rendered segmentation as a debugging aid or comparing it with another diff implementation.
Open the [cleanup modes example](/examples/cleanup-modes) to see all three render the same input side by side.
# Custom Rendering
> Style SvelteDiff with semantic classes or replace individual diff segments with Svelte 5 snippets.
**Source:** [https://diff.svelte.page/docs/guides/custom-rendering](https://diff.svelte.page/docs/guides/custom-rendering)
---
SvelteDiff offers two customization levels. `rendererClasses` preserves the built-in markup and changes its classes. Snippets replace the markup itself.
## Class-based styling
```svelte
```
```css
:global(.change--removed) {
background: #fee2e2;
color: #991b1b;
text-decoration: line-through;
}
:global(.change--inserted) {
background: #dcfce7;
color: #166534;
}
:global(.change--expected) {
background: #dbeafe;
border-bottom: 1px dashed #2563eb;
}
```
The classes are applied only to the built-in `` for that segment. A missing class falls back to the component's inline default for removed, inserted, or expected text.
## Direct child snippets
Use snippets when semantic HTML or richer UI matters:
```svelte
{#snippet remove(text: string)}
{text}
{/snippet}
{#snippet insert(text: string)}
{text}
{/snippet}
{#snippet expected(text: string, groupName: string)}
{text}
{/snippet}
{#snippet lineBreak()}
{/snippet}
```
## Renderer maps
Snippets can also be assembled into a `renderers` object. This is useful when a design system owns reusable diff renderers.
```svelte
{#snippet removed(text: string)}{text}{/snippet}
{#snippet inserted(text: string)}{text}{/snippet}
```
## Mixing strategies
Resolution is per type. A direct `insert` snippet can coexist with `renderers.remove`; equal text can still use the built-in fallback.
```svelte
{#snippet insert(text: string)}
{text}
{/snippet}
```
The direct child snippet wins for `insert`. The renderer map is used for `remove`. Everything else falls back to built-in rendering.
## Line breaks
The component splits multiline segments and calls `lineBreak` between lines. Override it when your output needs block separation, line numbers, or accessible separators.
Keep `white-space: pre-wrap` on the surrounding output if preserving other whitespace matters.
# Expected Patterns
> Mark intentional dynamic text such as dates, names, IDs, and versions as expected instead of noisy changes.
**Source:** [https://diff.svelte.page/docs/guides/expected-patterns](https://diff.svelte.page/docs/guides/expected-patterns)
---
Snapshots, generated files, invoices, and release notes often contain values that are supposed to change. Expected patterns let you label those regions separately instead of showing them as ordinary red/green edits.
## Named capture syntax
Put JavaScript-style named capture groups directly in `originalText`:
```svelte
v\\d+\\.\\d+\\.\\d+) on (?\\d{4}-\\d{2}-\\d{2})'}
modifiedText="Release v2.4.1 on 2026-07-17"
/>
```
The version and date render as `expected`. Their names and values are also available to rendering and callback code.
## Access captured values
```svelte
{
captures = nextCaptures ?? {}
}}
/>
{JSON.stringify(captures, null, 2)}
```
## Custom expected markup
```svelte
{#snippet expected(text: string, groupName: string)}
{text}
{/snippet}
```
## Flexible context matching
Patterns are matched using literal text around each named group as context. Extra content between the context and capture is tolerated. This is useful when the actual text adds punctuation or labels that the template does not include.
```text
Template: Copyright (?\d{4}) (?.+)
Actual: Copyright (c) 2026 Humanspeak, Inc.
```
`2026` and `Humanspeak, Inc.` can still be identified as the expected values while `(c)` remains a real insertion.
## Failure behavior
If the capture groups do not match, SvelteDiff cleans the template before computing the normal diff. Instead of exposing regex syntax to readers, it replaces each named group with a readable placeholder such as ``.
If `originalText` contains no named groups, the component follows the ordinary diff path with no extra matching work.
## Pattern safety
Named groups are discovered with an iterative parenthesis-counting parser rather than a backtracking regex. Escaped parentheses and nested non-named groups are supported. Nested named groups are rejected to keep group ownership unambiguous.
The pattern body is still compiled as JavaScript regular expression syntax. Treat patterns as trusted configuration, not untrusted user input.
## Good uses
- Timestamps in snapshots
- Generated IDs and build numbers
- Copyright years and holders
- Package versions in release output
- User names or environment-specific paths
Expected patterns are not a general ignore system: successful values stay visible, receive their own styling, and remain available through `captures`.
# Timing and Performance
> Measure SvelteDiff computation and cleanup time, set timeouts, and avoid unnecessary work with large inputs.
**Source:** [https://diff.svelte.page/docs/guides/performance](https://diff.svelte.page/docs/guides/performance)
---
# Timing & Performance
SvelteDiff computes whenever `originalText`, `modifiedText`, or a cleanup option changes. The `onProcessing` callback exposes the cost of that work.
## Compact equal-text DOM
`compact` defaults to `true`. Unstyled built-in equal segments render as text instead of
wrapper spans, reducing DOM weight without changing text content or intrinsic line breaks when no
selectors or styles depend on the legacy wrapper. Custom equal snippets, `renderers.equal`, and
`rendererClasses.equal` retain their requested markup.
Use the legacy DOM only when existing selectors or styles require equal spans:
```svelte
```
## Measure a diff
```svelte
(timing = nextTiming)}
/>
Core algorithm
{timing.main.toFixed(2)} ms
Cleanup
{timing.cleanup.toFixed(2)} ms
Total
{timing.total.toFixed(2)} ms
```
## Timeout
`timeout` is measured in seconds and maps to the underlying diff-match-patch timeout.
```svelte
```
The default is one second. Use `0` for no time limit. An unlimited timeout can be appropriate for controlled offline inputs, but is a poor default for arbitrary user content on the main thread.
The algorithm returns the best diff it has when the deadline is reached; timeout is not reported as an exception.
## Reactive input guidance
For large editor documents, debounce text input before updating the values passed to SvelteDiff. This keeps typing responsive and avoids recomputing intermediate states the reader never sees.
```typescript
let timer: ReturnType
function scheduleDiff(value: string) {
clearTimeout(timer)
timer = setTimeout(() => {
modifiedText = value
}, 200)
}
```
## Cleanup cost
`timing.cleanup` includes whichever cleanup pass was selected. Semantic cleanup generally does more readability work than efficiency cleanup. Measure with representative data instead of assuming the faster choice.
## Scope
The component performs character-level text diffing and renders the result. It does not virtualize large output, move computation to a worker, or expose incremental diff computation. For extremely large documents, consider preprocessing by line or using a specialized editor diff engine.
Use the [timing example](/examples/timing) to edit inputs and watch the callback values update.
# Migration Guide
> Migrate from the previous SvelteDiffMatchPatch name or a hand-built diff rendering loop to SvelteDiff.
**Source:** [https://diff.svelte.page/docs/migration](https://diff.svelte.page/docs/migration)
---
## 0.3.x to 0.4.0: compact equal text by default
Starting in 0.4.0, `compact` defaults to `true`. Unstyled built-in equal text no longer receives
unstyled wrapper `` elements. Text content and intrinsic line breaks are unchanged when no
selectors or styles depend on the legacy wrapper, and custom equal snippets, `renderers.equal`,
and `rendererClasses.equal` keep their requested markup.
If application CSS, tests, or DOM queries depend on the former equal spans, opt out while
migrating:
```svelte
```
Remove the opt-out after replacing selectors and styles that depend on unstyled equal ``
elements.
## From `SvelteDiffMatchPatch`
The component was renamed to `SvelteDiff`. The old export remains as a deprecated alias, so migration can be incremental.
```diff
- import { SvelteDiffMatchPatch } from '@humanspeak/svelte-diff'
+ import { SvelteDiff } from '@humanspeak/svelte-diff'
-
+
```
The default import already resolves to `SvelteDiff`:
```svelte
```
Rename deprecated types the same way:
| Deprecated | Current |
|---|---|
| `SvelteDiffMatchPatchProps` | `SvelteDiffProps` |
| `SvelteDiffMatchPatchTiming` | `SvelteDiffTiming` |
| `SvelteDiffMatchPatchDiff` | `SvelteDiffTuple` |
## From a custom `diff-match-patch` loop
A typical manual integration configures an instance, calls `diff_main`, runs cleanup, and maps operations to markup. SvelteDiff owns that wiring.
```svelte
{
console.log({ timing, diffs })
}}
/>
```
Move your operation-specific markup into `remove`, `insert`, and `equal` snippets. If your old implementation needs fuzzy matching or patch application, keep the lower-level library for that work—SvelteDiff deliberately exposes only the rendered text-diff use case.
## Callback field names
Current timing fields are `main`, `cleanup`, and `total`, all in milliseconds. Avoid older examples that refer to `computeTime` or `cleanupTime`.
## Expected patterns
Expected patterns are opt-in. Existing plain strings behave exactly as before. Only `originalText` values containing valid named capture groups activate expected-region matching.
## Verify the migration
1. Confirm both strings update reactively.
2. Compare cleanup mode output on representative documents.
3. Check custom snippets per segment type.
4. Update callback code to the current timing fields.
5. Add expected patterns only where variation is genuinely intentional.
---
# Comparisons
Compare Svelte Diff with alternative libraries.
- [jsdiff](https://diff.svelte.page/compare/vs-jsdiff.md): https://diff.svelte.page/compare/vs-jsdiff
- [diff-match-patch](https://diff.svelte.page/compare/vs-diff-match-patch.md): https://diff.svelte.page/compare/vs-diff-match-patch
- [diff2html](https://diff.svelte.page/compare/vs-diff2html.md): https://diff.svelte.page/compare/vs-diff2html
# Svelte Diff vs diff-match-patch
Algorithm Library vs Ready-to-Render Svelte 5 Component
## Overview
Google's diff-match-patch is the canonical text-diffing algorithm — and it is exactly what @humanspeak/svelte-diff runs internally (via the TypeScript port diff-match-patch-ts). The difference is everything around the algorithm: reactivity, cleanup wiring, rendering, and types, packaged as a Svelte 5 component instead of an imperative API you integrate by hand.
- **Svelte Diff site:** https://diff.svelte.page
- **Svelte Diff npm:** https://www.npmjs.com/package/%40humanspeak%2Fsvelte-diff
- **Svelte Diff slug:** svelte-diff
- **Category:** Diff algorithm library (Google)
- **Approach:** Imperative diff_main() API you wire into Svelte yourself
- **Website:** https://github.com/google/diff-match-patch
- **GitHub:** https://github.com/google/diff-match-patch
- **npm:** https://www.npmjs.com/package/diff-match-patch
## Feature comparison
| Feature | @humanspeak/svelte-diff | diff-match-patch | Notes |
| --- | --- | --- | --- |
| Diff algorithm | diff-match-patch (same core, TypeScript port) | diff-match-patch | |
| Ready-to-use Svelte component | Svelte 5 component | No — algorithm library | diff-match-patch exposes imperative APIs; you build and wire the Svelte UI |
| Semantic cleanup | cleanupSemantic prop | Manual diff_cleanupSemantic() call | |
| Efficiency cleanup | cleanupEfficiency edit-cost prop (default 4) | Manual call + editCost tuning | |
| Timeout guard | timeout prop | Diff_Timeout setting | |
| Expected patterns (ignore dynamic regions) | Named regex capture groups | No | |
| Rendering | Svelte snippets or CSS classes | diff_prettyHtml() — hard-coded inline styles, no rendering hooks | |
| TypeScript | First-class | Via separate @types/diff-match-patch package | |
| Actively maintained | Yes | No | Last npm release in 2020; Google archived the upstream repository |
| Fuzzy match & patch APIs | No | Yes | |
## Svelte Diff strengths
- Ready-to-use Svelte 5 component — pass two strings, get a rendered diff
- Svelte 5 runes-native — reactive to prop changes, no manual recompute
- Semantic and efficiency cleanup built in (readable diffs, not character noise)
- Expected patterns — mark dynamic regions (dates, names, versions) as "expected" with named regex capture groups instead of showing them as diffs
- Full rendering control via Svelte snippets (remove / insert / equal / expected / lineBreak) or plain CSS classes
- TypeScript-first with typed props, timing stats, and diff results
- Configurable timeout guard for large text comparisons
## diff-match-patch strengths
- The canonical diff algorithm, ported to many languages
- Proven at scale (originally built for Google Docs)
- Includes fuzzy match and patch application APIs
- Tiny with zero dependencies
## Svelte Diff limitations
- Smaller community (newer project)
- Character-level diffing with cleanup — no word / line / sentence granularity modes
- A Svelte component — not for diffing data in Node scripts or CLIs
## diff-match-patch limitations
- Unmaintained — last npm release in 2020, upstream repository archived
- Imperative API: you own the compute-on-change wiring, cleanup calls, and rendering
- diff_prettyHtml() uses hard-coded inline styles and provides no rendering hooks
- No bundled TypeScript types
## Verdict
If you were about to wire diff-match-patch into a Svelte component by hand — recomputing on prop changes, running cleanup, mapping operations to styled spans — that wrapper is literally what @humanspeak/svelte-diff is, built on a maintained TypeScript port. Reach for the raw library only when you need its fuzzy match / patch APIs or you are working outside Svelte.
## Keywords
diff-match-patch svelte, google diff match patch, diff match patch component, svelte diff match patch, diff-match-patch alternative
# Svelte Diff vs diff2html
Git-Patch HTML Generator vs Reactive Svelte 5 Component
## Overview
diff2html turns unified diff text — git patches — into polished, GitHub-style side-by-side or line-by-line HTML. It is the right tool for visualizing patches, and the wrong shape for comparing two strings inside a Svelte app: it needs pre-generated diff text as input and renders via an HTML string or imperative DOM wrapper plus a global stylesheet, rather than a Svelte component.
- **Svelte Diff site:** https://diff.svelte.page
- **Svelte Diff npm:** https://www.npmjs.com/package/%40humanspeak%2Fsvelte-diff
- **Svelte Diff slug:** svelte-diff
- **Category:** Git diff HTML renderer
- **Approach:** Convert unified diff / patch text into pre-styled HTML
- **Website:** https://diff2html.xyz
- **GitHub:** https://github.com/rtfpessoa/diff2html
- **npm:** https://www.npmjs.com/package/diff2html
## Feature comparison
| Feature | @humanspeak/svelte-diff | diff2html | Notes |
| --- | --- | --- | --- |
| Input | Two plain strings | Unified diff / git patch text | To compare two strings with diff2html you must generate patch text first (e.g. jsdiff createPatch) |
| Ready-to-use Svelte component | Svelte 5 component | No — HTML generator | diff2html generates or inserts HTML; it is not a Svelte component |
| Inline character-level diff | Yes | Within changed lines | |
| Side-by-side file view | No | Yes | |
| Git patch awareness (files, hunks, headers) | No | Yes | |
| Custom rendering | Svelte snippets | Template + CSS overrides | |
| Output | Real DOM via Svelte | HTML string or imperative DOM injection + stylesheet | |
| Expected patterns (ignore dynamic regions) | Named regex capture groups | No | |
| Semantic cleanup | cleanupSemantic prop | No | |
| TypeScript support | Yes | Yes | |
## Svelte Diff strengths
- Ready-to-use Svelte 5 component — pass two strings, get a rendered diff
- Svelte 5 runes-native — reactive to prop changes, no manual recompute
- Semantic and efficiency cleanup built in (readable diffs, not character noise)
- Expected patterns — mark dynamic regions (dates, names, versions) as "expected" with named regex capture groups instead of showing them as diffs
- Full rendering control via Svelte snippets (remove / insert / equal / expected / lineBreak) or plain CSS classes
- TypeScript-first with typed props, timing stats, and diff results
- Configurable timeout guard for large text comparisons
## diff2html strengths
- Polished GitHub-style diff UI out of the box
- Side-by-side and line-by-line view modes
- Understands real git patches — files, hunks, renames
- Framework-agnostic and maintained, with less frequent releases
## Svelte Diff limitations
- Smaller community (newer project)
- Character-level diffing with cleanup — no word / line / sentence granularity modes
- A Svelte component — not for diffing data in Node scripts or CLIs
- No side-by-side or per-file patch view
## diff2html limitations
- Requires unified diff text as input — comparing two strings means generating a patch first
- Renders via an HTML string or imperative DOM wrapper and a global stylesheet, not components
- Customization is CSS overrides, not your own markup
- Heavier payload than a single-purpose component
## Verdict
Choose diff2html to display git patches — PR-style file views with side-by-side layout. Choose @humanspeak/svelte-diff to compare two strings inline in a Svelte app, without generating patch text as an intermediate step.
## Keywords
diff2html svelte, svelte git diff view, diff2html vs svelte-diff, svelte diff viewer, svelte side by side diff
# Svelte Diff vs jsdiff
Algorithm Library vs Ready-to-Render Svelte 5 Component
## Overview
jsdiff (the npm "diff" package) is the default answer for text diffing in JavaScript — and it is excellent at computing diffs. But it renders nothing: every Svelte project that uses it re-implements the same change-object-to-markup loop. @humanspeak/svelte-diff is that missing rendering layer as a Svelte 5 component.
- **Svelte Diff site:** https://diff.svelte.page
- **Svelte Diff npm:** https://www.npmjs.com/package/%40humanspeak%2Fsvelte-diff
- **Svelte Diff slug:** svelte-diff
- **Category:** Diff algorithm library
- **Approach:** Compute change objects in JS, build your own rendering
- **Website:** https://github.com/kpdecker/jsdiff
- **GitHub:** https://github.com/kpdecker/jsdiff
- **npm:** https://www.npmjs.com/package/diff
## Feature comparison
| Feature | @humanspeak/svelte-diff | jsdiff | Notes |
| --- | --- | --- | --- |
| Computes text diffs | Yes | Yes | |
| Ready-to-use Svelte component | Svelte 5 component | No — algorithm library | jsdiff returns change objects; you build and wire the Svelte UI |
| Renders the diff for you | Yes | No | |
| Custom rendering | Svelte snippets (remove / insert / equal / expected) | Build your own from change objects | |
| Semantic cleanup | cleanupSemantic prop | No | jsdiff returns minimal diffs with no human-readability cleanup pass |
| Word / line / sentence modes | No | Yes | jsdiff ships diffWords, diffLines, diffSentences, diffJson |
| Expected patterns (ignore dynamic regions) | Named regex capture groups | No | |
| Reactive updates | Recomputes when props change | Manual recompute wiring | |
| Timing statistics | onProcessing callback | No | |
| Patch create / apply utilities | No | Yes | |
| TypeScript support | Yes | Yes | |
| Framework-agnostic | No | Yes | |
## Svelte Diff strengths
- Ready-to-use Svelte 5 component — pass two strings, get a rendered diff
- Svelte 5 runes-native — reactive to prop changes, no manual recompute
- Semantic and efficiency cleanup built in (readable diffs, not character noise)
- Expected patterns — mark dynamic regions (dates, names, versions) as "expected" with named regex capture groups instead of showing them as diffs
- Full rendering control via Svelte snippets (remove / insert / equal / expected / lineBreak) or plain CSS classes
- TypeScript-first with typed props, timing stats, and diff results
- Configurable timeout guard for large text comparisons
## jsdiff strengths
- Ubiquitous and battle-tested — the de-facto JS diffing library
- Framework-agnostic — works in Node, CLIs, workers, any frontend
- Multiple granularities: characters, words, lines, sentences, JSON
- Patch utilities (createPatch / applyPatch) for unified diff text
- Zero dependencies and actively maintained
## Svelte Diff limitations
- Smaller community (newer project)
- Character-level diffing with cleanup — no word / line / sentence granularity modes
- A Svelte component — not for diffing data in Node scripts or CLIs
## jsdiff limitations
- Renders nothing — every Svelte project re-implements the same {#each} rendering loop
- No semantic cleanup, so character-level diffs can be noisy
- No Svelte integration — reactivity and recompute wiring are on you
- Styling, escaping, and edge cases are your responsibility
## Verdict
Choose jsdiff when you need diff data — in Node, a CLI, or a fully custom UI you want to build from scratch. Choose @humanspeak/svelte-diff when the goal is a diff on screen in a Svelte app: it is the component you would otherwise hand-roll around a diff library, with cleanup, reactivity, and rendering already done.
## Keywords
jsdiff svelte, svelte text diff, render diff in svelte, jsdiff vs svelte-diff, svelte diff component
---
## External links
- [npm](https://www.npmjs.com/package/@humanspeak/svelte-diff)
- [GitHub](https://github.com/humanspeak/svelte-diff)
- [Issue tracker](https://github.com/humanspeak/svelte-diff/issues)
- [Humanspeak](https://humanspeak.com)