Library / SDK
rtfpessoa/diff2html avatar
rtfpessoa/diff2html

diff2html publishes three UI bundles, and its ES6 file list reuses the ES5 paths

Pretty diff to html javascript library (diff2html)

3,415 stars302 forksTypeScriptMIT

At a glance

What is it?
diff2html renders git and unified diffs as HTML. Its manifest still says 3.0.0-beta.1 while releases have reached 3.4.55, the ES6 distribution list links the same three UI files as the ES5 list, the badge block repeats one npm image nine times, and the build writes generated templates back into the source tree.
Who is it for?
diff2html is a sensible choice when you already have diff text and want a presentable result rather than a diff algorithm, since it parses unified and git format and gives you either a wrapper for the browser or the parser and generator directly. Two things to know before you pick a build.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 153 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 4, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Three UI bundles differ only by how much highlighting they carry

The distributions section is where most people land, and it has a defect in it. The browser list names four files: diff2html.min.js, which is the parser and the HTML generator with no wrapper, then three UI bundles. diff2html-ui.min.js includes the wrapper with highlight.js support for all its languages. diff2html-ui-slim.min.js includes the wrapper with what the documentation calls the most common languages. diff2html-ui-base.min.js includes the wrapper with no highlight.js implementation at all, so you can use it without syntax highlighting or pass your own implementation. Below that, the Node library list is split into ES5 and ES6, and the ES5 entries are correct, but the three ES6 UI entries point at the same lib/ui/js paths as the ES5 ones. Only the ES6 core file changes to lib-esm.

The manifest says 3.0.0-beta.1 and the releases say 3.4.55

The version field in the repository's package.json reads 3.0.0-beta.1. The published releases tell a different story: 3.4.55 on 2026-01-01, whose title is the commit message Use @profoundlogic/hogan, then 3.4.24 and 3.4.23, both published on the same evening of 2023-01-06, twenty-eight minutes apart. So there is a three year gap between the last two releases of the 3.4.2x line and the next one, and the numbering advanced by thirty-one patch versions with no tags in between. The last push to the default branch master is dated 2026-05-08. Read the manifest as a placeholder rather than a version, and pin from the registry instead.

ts
constructor(target: HTMLElement, diffInput?: string | DiffFile[]) // diff2html-ui, diff2html-ui-slim
constructor(target: HTMLElement, diffInput?: string | DiffFile[], config: Diff2HtmlUIConfig = {}, hljs?: HighlightJS) // diff2html-ui-base

The build compiles templates into a file inside src

The build is six steps, and every one of them starts by deleting its output directory before writing. build:css runs postcss over the stylesheet into bundles/css, build:commonjs and build:esm each remove their directory and run tsc with a different module target, build:bundles runs webpack in production mode, and build:website does the same for the site. The interesting one is build:templates, which runs a script called hulk through ts-node, globs the mustache files under src/templates, and writes the result into src/diff2html-templates.ts as a wrapped TypeScript variable. So the HTML templates are not loaded at runtime; they are compiled into a source file, and a build mutates the source tree rather than only its output. That is also why a clean checkout has no rendered templates until you build.

The same feature can be a config default or a method call

The wrapper exposes four features, and each one appears twice. In the configuration list, synchronisedScroll defaults to true, highlight defaults to true and fileListToggle defaults to true, while fileListStartVisible defaults to false and fileContentToggle decides whether each file's contents can be collapsed. Then the methods section offers synchronisedScroll, fileListToggle taking a startVisible argument, highlightCode and stickyFileHeaders as functions you call yourself. So a scroll sync can be on by default or switched on imperatively, and the file list can be configured or opened at draw time. Two of the four have no counterpart in the visible configuration list, which matters most for the base bundle: highlightCode is listed as a method, but the base build ships no highlighting implementation to call.

Combined and word diffs are refused at the door

The input contract is narrow and stated in a few lines. diff2html accepts the text contents of a unified diff, or the superset format that git diff produces, and explicitly not combined diffs and not word diffs. To pass several files you concatenate the diffs, exactly the way git diff prints them for a multi file change. There is no path that takes a repository or a commit pair, so anything that produces diff text first, from a server, a build step or a stored patch, works and anything that wants a diff generated for it does not. The constructor also accepts a DiffFile array, which is the only structured input mentioned, and the two overloads differ only in the extra configuration and HighlightJS arguments available to the base build.

engines asks for node 12 while the tooling says otherwise

The manifest declares engines node >=12, which is the floor for consuming the package rather than for building it, and the gap between the two is wide. The build uses ts-node, webpack with configuration written in TypeScript, postcss, and an eslint flat config in an .mjs file, none of which belong to a node 12 toolchain. Two smaller things sit in the same file. The repository url uses the git protocol, git://github.com/rtfpessoa/diff2html.git, which GitHub no longer serves, so a clone that copies it will fail. And the keyword list contains the word pretty twice, at positions three and ten, so search ranking gets one less signal than it looks like it should.

One badge is repeated nine times and another links to nothing

The header of the README is mostly badges, and the arrangement has been edited carelessly. The same npm package badge appears in a run of nine, the first eight of them consecutive, which means eight identical images render in a row before the jsdelivr badge and the contributors badge. That last one is worse: it is an image whose link target is an in-page anchor, so clicking the contributors badge scrolls the current page rather than going anywhere. Neither is harmful, but both are the kind of thing that makes a project look abandoned to a first-time visitor even when the commits behind it are recent. The features list itself is short and unfussy, naming git and unified support, line by line and side by side output, old and new line numbers, a GitHub like style, syntax highlighting and line similarity matching.

The documentation site is deployed with Terraform and a CNAME

The site is not a GitHub Pages project managed by hand. A CNAME file sits at the repository root, which is how the custom domain is attached, and a terraform directory sits beside it, so the hosting is described as code. Two webpack configurations build the two outputs, one for the bundles and one for the website, and the website output is written into a docs directory that the build script deletes first. Around that are the usual pieces of a maintained TypeScript project: jest.config.js for tests, a husky directory for commit hooks, an all-contributorsrc with a CREDITS.md beside it, an eslint flat config with its own separate tsconfig.eslint.json, and a scripts directory holding the template compiler that the build calls.

Editorial conclusion

diff2html is a sensible choice when you already have diff text and want a presentable result rather than a diff algorithm, since it parses unified and git format and gives you either a wrapper for the browser or the parser and generator directly. Two things to know before you pick a build. The three browser bundles differ only in how much syntax highlighting they carry, so the size difference between the full and base builds is a highlight.js decision rather than a rendering one. And the manifest's own version string does not describe what is published, so pin the npm version rather than reading the repository, and expect the documentation to be a little behind the code: the distribution list contains a copy-paste error and the README gives no install command at all.

Frequently asked questions

How do I install diff2html?

The README gives no install command. It lists a jsdelivr CDN, a WebJar, the Node library published as the diff2html package on npm, a separate CLI published as diff2html-cli, and manual browser bundles you can load from jsdelivr. The actual build commands live in the manifest's scripts rather than in the documentation.

How do I use diff2html to render a diff in a page?

There are two entry points. Diff2HtmlUI is a wrapper that takes a target element plus diff text or a DiffFile array, injects the HTML, and adds a collapsible file summary list and syntax highlighting. Diff2Html is the parser and generator used directly, which gives you control over the JSON or the HTML it produces.

Which diff formats does diff2html accept as input?

The text contents of a unified diff, or the superset format that git diff produces. Combined diffs and word diffs are not accepted, and to pass several files you concatenate the diffs, the same way git diff prints them for a multi file change.

Which diff2html bundle should I load from a CDN?

diff2html-ui.min.js includes highlight.js support for all its languages, diff2html-ui-slim.min.js covers the most common languages only, and diff2html-ui-base.min.js ships no highlight.js implementation, so it can run without highlighting or accept your own. The base build's constructor is the one that takes a configuration object and a HighlightJS instance.

Why does the diff2html repository show an old version number?

The package.json in the repository reads 3.0.0-beta.1, which is a placeholder rather than what is published. Releases have reached 3.4.55 on 2026-01-01, and the two before that gap, 3.4.23 and 3.4.24, were both published on 2023-01-06. The last push to master is dated 2026-05-08.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. rtfpessoa/diff2html on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/rtfpessoa-diff2html.svg)](https://hysenlabs.com/projects/rtfpessoa-diff2html)