entities, he, html-entities, and sanitize-html are widely used npm packages for handling HTML content in JavaScript applications. All four address aspects of working with HTML strings — specifically encoding or decoding HTML entities (like converting & to & or vice versa). However, they differ significantly in scope: entities, he, and html-entities focus exclusively on low-level entity transformations, while sanitize-html is a higher-level security tool that removes dangerous HTML to prevent XSS attacks, using entity decoding as part of its process. These libraries are essential when rendering user-generated content, processing rich text, or interfacing with APIs that return escaped HTML.
When working with HTML strings in JavaScript — whether rendering user content, parsing RSS feeds, or building static site generators — you’ll inevitably face two related but distinct problems: (1) correctly converting between raw characters and their escaped HTML entity forms (e.g., & ↔ &), and (2) safely displaying untrusted HTML without exposing your app to XSS attacks. The packages entities, he, html-entities, and sanitize-html all touch this space, but they solve different layers of the problem. Let’s break down what each does, how they work, and when to use which.
entities: Low-Level, Spec-Aware Entity Conversionentities is a minimal, zero-dependency library built for speed and correctness in entity encoding and decoding. It doesn’t pretend to be a sanitizer — it only handles the conversion between plain text and HTML/XML entities. It supports both named (©) and numeric (©) references and lets you choose decoding modes (strict, loose, etc.).
// Using entities
import { encode, decode } from 'entities';
const encoded = encode('AT&T > 5 & < 10');
// Result: 'AT&T > 5 & < 10'
const decoded = decode('<script>alert("xss")</script>');
// Result: '<script>alert("xss")</script>'
Note: This does not remove the <script> tag — it only decodes entities. That’s intentional.
he: HTML5-Compliant Entity Handlinghe (short for “HTML Entities”) strictly implements the HTML5 specification for entity parsing. It’s battle-tested and used in projects like Markdown parsers where spec compliance matters. Like entities, it only encodes/decodes — no sanitization.
// Using he
import { encode, decode } from 'he';
const encoded = encode('foo © bar ≠ baz 𝌆 qux');
// Result: 'foo © bar ≠ baz 𝌆 qux'
const decoded = decode('<img src=x onerror=alert(1)>');
// Result: '<img src=x onerror=alert(1)>'
Again, dangerous HTML remains intact — he assumes you’ll handle security separately.
html-entities: Class-Based API with Multiple Standardshtml-entities takes a more object-oriented approach. You instantiate encoders/decoders for specific standards (HTML4, HTML5, XML), which is handy if your app deals with mixed document types.
// Using html-entities
import { Html5Entities } from 'html-entities';
const entities = new Html5Entities();
const encoded = entities.encode('5 > 3 & 2 < 4');
// Result: '5 > 3 & 2 < 4'
const decoded = entities.decode('<div onclick="steal()">Click me</div>');
// Result: '<div onclick="steal()">Click me</div>'
The class-based design allows reuse with consistent settings, but adds slight overhead compared to function-based alternatives.
sanitize-html: Security-First HTML Cleaningsanitize-html is in a different category. Its job isn’t just decoding — it’s removing unsafe HTML to prevent XSS. It parses the input into a DOM-like structure, walks the tree, and strips disallowed tags/attributes based on a configurable allowlist.
// Using sanitize-html
import sanitizeHtml from 'sanitize-html';
const dirty = '<script>alert("xss")</script><p>Hello <b>world</b>!</p>';
const clean = sanitizeHtml(dirty);
// Result: '<p>Hello <b>world</b>!</p>'
// It also decodes entities during parsing
const withEntities = '<img src=x onerror=alert(1)>';
const cleaned = sanitizeHtml(withEntities);
// Result: '' (empty string — no valid tags after decoding)
Crucially, sanitize-html always decodes entities as part of parsing, so you never see raw < in the output — only the actual < character, which is then evaluated for safety.
If your task is purely transforming text ↔ entities (e.g., preparing strings for HTML insertion or parsing API responses that return escaped HTML), do not use sanitize-html. It’s overkill: it parses full HTML, walks a DOM tree, and applies rules — all unnecessary overhead.
Between entities, he, and html-entities:
entities is fastest and smallest. Use it in performance-sensitive contexts (e.g., SSR at scale).he is best when you must match browser behavior exactly (e.g., in a Markdown-to-HTML pipeline).html-entities shines when you need to switch between XML/HTML4/HTML5 modes or reuse configured instances.If you’re rendering user-provided HTML (from a CMS, comment box, or WYSIWYG editor), only sanitize-html is appropriate. The others will happily give you executable script tags if the input contains them — even after decoding.
Example of why this matters:
// ❌ Dangerous: using a decoder alone
const userInput = '<script>stealCookies()</script>';
const decoded = decode(userInput); // from any of the first three libs
// decoded = '<script>stealCookies()</script>'
document.body.innerHTML = decoded; // 💥 XSS vulnerability!
// ✅ Safe: using sanitize-html
const clean = sanitizeHtml(userInput);
// clean = '' (script tag removed)
document.body.innerHTML = clean; // safe
sanitize-html also supports advanced features like:
rel="noopener" to links)You fetch blog posts from a REST API that returns titles like "Why 5 > 3 Matters". You just need to display the real characters.
✅ Best choice: entities or he
// Simple decoding
const title = decode(apiResponse.title); // "Why 5 > 3 Matters"
No sanitization needed — the data is trusted.
Your SSG processes Markdown files that may contain inline HTML. You need to encode code snippets for HTML output but also ensure user-authored HTML doesn’t break layout or introduce scripts.
✅ Best combo: Use entities for encoding code blocks + sanitize-html for final output.
// Encode special chars in code
const codeHtml = `<code>${encode(codeString)}</code>`;
// Later, sanitize full page HTML
const finalHtml = sanitizeHtml(pageWithUserHtml);
Your app has a rich text editor (e.g., TinyMCE) that outputs HTML like <p>Hello <strong>you</strong></p>. You must store and later render this safely.
✅ Only choice: sanitize-html
const cleanHtml = sanitizeHtml(userHtml, {
allowedTags: ['p', 'strong', 'em', 'a'],
allowedAttributes: { 'a': ['href'] }
});
Never decode first — let sanitize-html handle parsing and cleaning in one secure step.
| Package | Primary Purpose | Handles XSS? | API Style | Best For |
|---|---|---|---|---|
entities | Fast entity conversion | ❌ | Functional | Parsers, SSR, minimal dependencies |
he | HTML5-spec compliance | ❌ | Functional | Tools needing exact browser-like behavior |
html-entities | Multi-standard support | ❌ | Class-based | Apps switching between XML/HTML4/HTML5 modes |
sanitize-html | HTML sanitization | ✅ | Functional | Rendering untrusted user-submitted HTML |
entities for intermediate encoding and sanitize-html for final output.Remember: entity decoding and HTML sanitization are related but separate responsibilities. Choose the right tool for the job — your app’s security and performance depend on it.
Choose entities if you need a lightweight, dependency-free library focused purely on accurate and fast HTML/XML entity encoding and decoding. It supports both named (<) and numeric (<) entities and offers fine-grained control over decoding strictness. Ideal for parsers, compilers, or SSR frameworks where minimal footprint and correctness are critical.
Choose he if you want a well-tested, spec-compliant utility that strictly follows the HTML5 standard for entity handling. It provides clear separation between encoding and decoding with options like useNamedReferences. Best suited for applications requiring standards fidelity, such as content processors or tools that must match browser behavior exactly.
Choose html-entities if you prefer a more ergonomic API with class-based instantiation and support for multiple character sets (e.g., XML, HTML4, HTML5). It’s convenient when you need to reuse encoder/decoder instances with consistent settings across a codebase, though it’s slightly heavier than alternatives due to its modular design.
Choose sanitize-html only when your primary goal is to safely render untrusted HTML by stripping malicious tags and attributes — not just entity conversion. It uses entity decoding internally but focuses on XSS prevention through allowlists, transforms, and deep DOM traversal. Never use it solely for encoding/decoding; use it when accepting user-submitted HTML (e.g., from WYSIWYG editors).
Encode & decode HTML & XML entities with ease & speed.
entities is used by many popular libraries; eg.
htmlparser2, the official
AWS SDK and
commonmark use it to process
HTML entities.entities is the fastest library for decoding HTML entities (as of
September 2025); see performance.entitiesnpm install entities
entitiesconst entities = require("entities");
// Encoding
entities.escapeUTF8("& ü"); // "&#38; ü"
entities.encodeXML("& ü"); // "&#38; ü"
entities.encodeHTML("& ü"); // "&#38; ü"
// Decoding
entities.decodeXML("asdf & ÿ ü '"); // "asdf & ÿ ü '"
entities.decodeHTML("asdf & ÿ ü '"); // "asdf & ÿ ü '"
Benchmarked in September 2025 with Node v24.6.0 on Apple M2 using tinybench.
Higher ops/s is better; avg (μs) is the mean time per operation.
See scripts/benchmark.ts to reproduce.
| Library | Version | ops/s | avg (μs) | ±% | slower |
|---|---|---|---|---|---|
| entities | 7.0.0 | 5,838,416 | 175.57 | 0.06 | — |
| html-entities | 2.6.0 | 2,919,637 | 347.77 | 0.33 | 50.0% |
| he | 1.2.0 | 2,318,438 | 446.48 | 0.70 | 60.3% |
| parse-entities | 4.0.2 | 852,855 | 1,199.51 | 0.36 | 85.4% |
| Library | Version | ops/s | avg (μs) | ±% | slower |
|---|---|---|---|---|---|
| entities | 7.0.0 | 2,770,115 | 368.09 | 0.11 | — |
| html-entities | 2.6.0 | 1,491,963 | 679.96 | 0.58 | 46.2% |
| he | 1.2.0 | 481,278 | 2,118.25 | 0.61 | 82.6% |
| Library | Version | ops/s | avg (μs) | ±% | slower |
|---|---|---|---|---|---|
| entities | 7.0.0 | 4,616,468 | 223.84 | 0.17 | — |
| he | 1.2.0 | 3,659,301 | 280.76 | 0.58 | 20.7% |
| html-entities | 2.6.0 | 3,555,301 | 296.63 | 0.84 | 23.0% |
Note: Micro-benchmarks may vary across machines and Node versions.
What methods should I actually use to encode my documents?
If your target supports UTF-8, the escapeUTF8 method is going to be your best
choice. Otherwise, use either encodeHTML or encodeXML based on whether
you're dealing with an HTML or an XML document.
You can have a look at the options for the encode and decode methods to see
everything you can configure.
When should I use strict decoding?
When strict decoding, entities not terminated with a semicolon will be ignored. This is helpful for decoding entities in legacy environments.
Why should I use
entitiesinstead of alternative modules?
As of September 2025, entities is faster than other modules. Still, this is
not a differentiated space and other modules can catch up.
More importantly, you might already have entities in your dependency graph
(as a dependency of eg. cheerio, or htmlparser2), and including it directly
might not even increase your bundle size. The same is true for other entity
libraries, so have a look through your node_modules directory!
Does
entitiessupport tree shaking?
Yes! entities ships as both a CommonJS and a ES module. Note that for best
results, you should not use the encode and decode functions, as they wrap
around a number of other functions, all of which will remain in the bundle.
Instead, use the functions that you need directly.
This library wouldn't be possible without the work of these individuals. Thanks to
he, which was one of the inspirations
for entitiesparse5 projecthtml-entities library. entities
would be quite a bit slower if there wasn't any competition. Right now
entities is on top, but we'll see how long that lasts!License: BSD-2-Clause
To report a security vulnerability, please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure.
entities for enterpriseAvailable as part of the Tidelift Subscription
The maintainers of entities and thousands of other packages are working with
Tidelift to deliver commercial support and maintenance for the open source
dependencies you use to build your applications. Save time, reduce risk, and
improve code health, while paying the maintainers of the exact dependencies you
use.
Learn more.