Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Htmldiff Laravel Package

ssddanbrown/htmldiff

A PHP library for generating a visual diff between two HTML strings. It compares content word by word while preserving HTML structure, outputting marked-up HTML with inserted and deleted content highlighted, useful for showing edits to rich-text content.

Deep Wiki
Context7

Getting Started

Install via Composer:

composer require ssddanbrown/htmldiff

Because the upstream repository is archived and only migrated to Codeberg, treat the last tagged release (2024-03-29) as the effective "latest" and pin it explicitly in composer.json so a mirror or tag rewrite cannot surprise you:

"ssddanbrown/htmldiff": "0.0.5"

Where to look first:

  1. The README on Codeberg (the GitHub repo is a redirect shell) — it documents the two-argument constructor and build() call.
  2. src/Diff.php — this is the only class most users touch; it is the public API surface (new Diff($old, $new)->build()).
  3. src/ internals only if you need to inspect how block elements are tokenized.

First use case — comparing two rendered HTML snapshots (e.g. two revisions of a CMS page, a blog post preview, or a settings/notification body):

use ssddanbrown\HtmlDiff\Diff;

$old = '<p>The quick brown fox.</p>';
$new = '<p>The quick red fox jumped.</p>';

$diffHtml = (new Diff($old, $new))->build();
// => markup with additions/removals highlighted for display

The output is display-ready HTML, not a data structure — it is meant to be echoed, styled with CSS on <ins>/<del>, and shown to a human. That framing should drive everything below: think of this as a presentation library, not a programmatic diff engine.

Implementation Patterns

Revision comparison in a CMS/wiki model. The canonical day-to-day pattern is a compare action that loads two versions and renders the diff:

public function compare(Revision $a, Revision $b)
{
    $diff = (new Diff($a->html, $b->html))->build();

    return view('revisions.compare', [
        'diff'  => $diff,
        'a'     => $a,
        'b'     => $b,
    ]);
}

Blade integration. Echo raw, since the point is to render HTML:

<div class="diff">{!! $diff !!}</div>

Style the additions and removals via CSS rather than post-processing the string:

.diff ins { background: #d4f8c4; text-decoration: none; }
.diff del { background: #f8d4d4; }

Observer / activity-log pattern. If you keep a change feed, generate the diff lazily (on request) or store the inputs (both HTML blobs) and compute on read — storing the diff output itself couples your schema to the library and its markup.

Test assertions. Because the output is HTML, a useful trick is to assert against normalized output:

$diff = (new Diff('<p>a</p>', '<p>b</p>'))->build();

$this->assertStringContainsString('<ins', $diff);
$this->assertStringContainsString('<del', $diff);

Chaining with existing rendering. If your content is Markdown, render both versions to HTML first and diff the HTML — diffing Markdown source produces noise because a single syntax change (e.g. * to **) can shuffle many characters. Diff the rendered surfaces you actually care about.

Integration tip — wrap it. Create a tiny HtmlDiffService so callers don't import the vendor namespace directly. When the package is eventually retired you swap one class, not every call site:

class HtmlDiffService
{
    public function compare(string $old, string $new): string
    {
        return (new Diff($old, $new))->build();
    }
}

Gotchas and Tips

Archived and single-maintainer. The GitHub repo is a migration notice; releases are frozen. Pin the version, watch Codeberg for security-relevant changes, and keep the wrapper above so a drop-in replacement is a one-file change. Don't build new architecture assuming this library will evolve.

The output is trusted HTML — treat it as such. The library inserts <ins>/<del> markup into content derived from your stored HTML. If either input is user-supplied, sanitize before diffing or make sure your storage path already sanitized. Rendering {!! $diff !!} is only safe because you trust the inputs — do not assume the library sanitizes.

HTML, not text. This is not a general-purpose string diff. Diffing raw CSS, JSON, or Markdown will produce awkward output because the algorithm expects HTML block structure. Render first, diff second.

Whitespace can create noise. Formatting differences (\n between tags, indentation) may surface as changes even when the rendered result is identical. If your editor or template engine reformats before saving, normalize the HTML you store (or accept cosmetic diff noise).

Large documents are expensive. The diff runs on every request that calls build(). For big pages, cache the result keyed on both revision IDs (cache()->remember("diff:{$a->id}:{$b->id}", ...)) and invalidate on new revisions.

Don't parse the output. Avoid regular expressions over the diff HTML to extract "what changed." If you need structured change data, use a dedicated diff (or parse both DOMs yourself) — the output here is presentation-oriented and its exact markup/tag nesting is an implementation detail that can change between versions.

Namespace and class name. The namespace is ssddanbrown\HtmlDiff and the entry point is Diff (i.e. new Diff(...)->build()). The short name collides conceptually with other diff libraries; alias it on import if you use more than one.

Extension points are minimal. There is no documented hook system for customizing how blocks are compared or rendered — styling lives in your CSS, not in the library. If you need control over which elements are diffed (e.g., ignoring timestamps or "last edited" footers), strip those from the HTML before calling build() rather than expecting an option flag.

Debugging tip. When output looks wrong, reduce to the smallest pair of strings that reproduces it: dump $old and $new with var_export and diff those first. Most "the diff is weird" reports turn out to be unexpected HTML in one input (unclosed tags, entity encoding differences), not a library bug.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin