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:
<SvelteDiff
originalText={'Release (?<version>v\\d+\\.\\d+\\.\\d+) on (?<date>\\d{4}-\\d{2}-\\d{2})'}
modifiedText="Release v2.4.1 on 2026-07-17"
/><SvelteDiff
originalText={'Release (?<version>v\\d+\\.\\d+\\.\\d+) on (?<date>\\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. Capture names must be globally unique across the entire template, including separate lines; duplicate names are rejected even when their values would be equal.
Access captured values
<script lang="ts">
let captures = $state<Record<string, string>>({})
</script>
<SvelteDiff
{originalText}
{modifiedText}
onProcessing={(_timing, _diffs, nextCaptures) => {
captures = nextCaptures ?? {}
}}
/>
<pre>{JSON.stringify(captures, null, 2)}</pre><script lang="ts">
let captures = $state<Record<string, string>>({})
</script>
<SvelteDiff
{originalText}
{modifiedText}
onProcessing={(_timing, _diffs, nextCaptures) => {
captures = nextCaptures ?? {}
}}
/>
<pre>{JSON.stringify(captures, null, 2)}</pre>Custom expected markup
Built-in expected-region spans expose data-capture-name and data-capture-value alongside the hover title. Use element.dataset.captureName and element.dataset.captureValue for richer tooltips. Each fragment of a multiline capture carries the full captured value. Custom snippets own their markup; this example exposes their supplied text, while onProcessing provides full capture values.
<SvelteDiff {originalText} {modifiedText}>
{#snippet expected(text: string, groupName: string)}
<span class="expected" data-capture-name={groupName} data-capture-value={text} title={`Matched ${groupName}`}>
{text}
</span>
{/snippet}
</SvelteDiff><SvelteDiff {originalText} {modifiedText}>
{#snippet expected(text: string, groupName: string)}
<span class="expected" data-capture-name={groupName} data-capture-value={text} title={`Matched ${groupName}`}>
{text}
</span>
{/snippet}
</SvelteDiff>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.
Template: Copyright (?<year>\d{4}) (?<holder>.+)
Actual: Copyright (c) 2026 Humanspeak, Inc.Template: Copyright (?<year>\d{4}) (?<holder>.+)
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
Invalid recognized regex bodies or duplicate capture names reject the whole template. SvelteDiff compares the original source literally, and captures is undefined. For example, (?<bad>*) stays (?<bad>*) in the compared source.
If a valid parsed template does not match its target, SvelteDiff cleans it before computing the normal diff, and captures is undefined. Each named group becomes a readable placeholder: Copyright (?<year>\d{4}) MIT compared with different text uses Copyright <year> MIT as its source.
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. The algorithm timeout does not bound regex extraction.
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.
Word and line modes
All diff modes retain extraction → resolved/cleaned source → diff → tagging. Tokenization operates on resolved text for matched templates; valid unmatched templates use cleaned placeholders, while invalid or duplicate templates retain the original literal source. Raw callback tuples reconstruct that source and the original modified text exactly. Expected annotations can split displayed words or lines, so whole-token guarantees apply to raw tuples, not snippet invocations. Newline rendering can also split tuples.
<script lang="ts">
import SvelteDiff from '@humanspeak/svelte-diff'
const template = 'Release (?<version>v\\d+)'
const actual = 'Release v2 ready'
</script>
<SvelteDiff originalText={template} modifiedText={actual} diffMode="line" /><script lang="ts">
import SvelteDiff from '@humanspeak/svelte-diff'
const template = 'Release (?<version>v\\d+)'
const actual = 'Release v2 ready'
</script>
<SvelteDiff originalText={template} modifiedText={actual} diffMode="line" />Resolved source is Release v2. Line mode returns [[-1, "Release v2"], [1, "Release v2 ready"]]. The deletion includes the captured value v2, while the target annotates v2 as expected with group name version. Removals remain removals and are never hidden to avoid this duplication. Word/line skip both cleanup options.