# @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.
---
## 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)