html-escaper

A tiny, zero-dependency utility that safely escapes and unescapes HTML entities in JavaScript strings.

Library
npm
v3.0.3
112stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
30/100Needs Attention
Development Activity0
Maintenance0
Community48
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
50/100Fair
Architecture60
Code Quality40
Innovation65
Learning Curve35

html-escaper is a minimal JavaScript module for converting the five HTML-sensitive characters (&, <, >, ', ") to and from their entity forms. Rather than chaining multiple .replace() calls character-by-character — a common anti-pattern that can produce double-encoding bugs and even reopen XSS holes when unescaping — it performs a single regex pass paired with a plain-object lookup map, so every character is matched and replaced in one traversal of the string.

The package ships as ESM-only from version 3 onward, with a generated CommonJS build for compatibility and a minified UMD bundle for direct browser use via <script> tags. It has no runtime dependencies, a tiny footprint, and an API surface of exactly two functions: escape and unescape.

What You Get

  • An escape(string) function that converts &, <, >, ', and " to their HTML entity equivalents in one pass
  • An unescape(string) function that reverses the process, correctly handling both named (&amp;) and numeric (&#38;) entity forms
  • Zero runtime dependencies and a sub-1KB minified footprint
  • Dual ESM/CJS builds plus a UMD min.js bundle for direct browser <script> usage

Common Use Cases

  • Escaping user-supplied text before injecting it into HTML templates to prevent XSS
  • Sanitizing values before setting innerHTML or building HTML strings on the server
  • Round-tripping content that was previously escaped for storage or transport, via unescape
  • Lightweight alternative to larger sanitization libraries when only entity escaping is needed, not full HTML parsing

Under The Hood

Architecture The entire module lives in a single index.js file (mirrored as esm/index.js for the ESM build) with no internal layering: two plain lookup objects (esca for escaping, unes for unescaping) map each character or entity to its counterpart, and String.prototype.replace is invoked once per direction with a replacer function that looks up the match in the corresponding object. This single-pass design is the module’s entire reason for existing — the README explicitly documents the double-encoding bug that results from chaining separate .replace(/&/g,...).replace(/</g,...) calls, and the architecture is built specifically to avoid it by matching all target characters with one combined regex (/[&<>'"]/g for escaping, an alternation of entity patterns for unescaping) before any substitution happens.

Tech Stack The package has zero runtime dependencies. Its source is authored as a native ES module (type: module in package.json) and is transformed into a CommonJS build via the ascjs dev dependency, with rollup producing a UMD bundle that uglify-es then minifies for the unpkg-served min.js. Tests run under c8 for coverage reporting, invoked via a plain node ./test/index.js — no test framework is used. CI historically ran on Travis (.travis.yml, targeting a single “stable” Node version).

Code Quality The test suite is a single file (test/index.js) containing four console.assert calls that check escape/unescape correctness in both normal and “inverted” character order — there is no assertion library, no test runner, and console.assert does not throw or fail the process on a failed assertion, so a regression could pass silently in some environments. There are no TypeScript types shipped in the repository itself, no ESLint or Prettier configuration, and the Travis CI badge points at an integration that is no longer actively used by most projects. The source itself, however, is small, readable, and thoroughly commented with JSDoc describing exact behavior and edge cases.

What Makes It Unique The module isn’t notable for new functionality — escaping HTML entities is a well-worn problem — but for the specific correctness argument it makes and enforces in its own implementation: the README walks through exactly how naive chained .replace() escaping and unescaping can produce double-encoded output or reopen an XSS vector, and the single-combined-regex design exists purely to close that gap. It intentionally stays minimal, referring users elsewhere (html-sloppy-escaper, he, lodash) if they need broader character coverage or more permissive input handling.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search