Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions docs/modules/sanitize-html.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
description: Replacing sanitize-html with neosanitize, a zero-dependency, isomorphic HTML sanitizer with a drop-in legacy engine and a faster WHATWG-based engine
---

# Replacements for `sanitize-html`

[`sanitize-html`](https://github.com/apostrophecms/sanitize-html) is a widely used HTML sanitizer, but it pulls in a large dependency tree (including `htmlparser2`, `parse-srcset`, `postcss`, and others) and only runs in Node-like environments.

[`neosanitize`](https://github.com/PuruVJ/neosanitize) is a zero-dependency, isomorphic (works in Node, browsers, and edge runtimes) HTML sanitizer written in TypeScript. It ships two engines:

- A **legacy** engine (`neosanitize/legacy`) that is a byte-identical, drop-in port of `sanitize-html` 2.x — same API, same options, same output.
- A **root** engine (`neosanitize`) built on a fast, browser-faithful WHATWG parser with a deny-by-default policy, recommended for new code and for the best performance and security.

## `neosanitize/legacy` (drop-in replacement)

The legacy engine mirrors the `sanitize-html` API and output exactly, so migrating is usually just a matter of changing the import:

```ts
import sanitizeHtml from 'sanitize-html' // [!code --]
import sanitizeHtml from 'neosanitize/legacy' // [!code ++]

const clean = sanitizeHtml(dirty, {
allowedTags: ['b', 'i', 'em', 'strong', 'a'],
allowedAttributes: {
a: ['href']
}
})
```

All `sanitize-html` options (`allowedTags`, `allowedAttributes`, `allowedSchemes`, `transformTags`, `exclusiveFilter`, etc.) are supported with identical behaviour.

## `neosanitize` (recommended)

For new code, the root module is recommended. It is built on a fast, browser-faithful WHATWG parser (100% html5lib tokenizer conformance) and follows a deny-by-default policy, so only what you explicitly allow gets through:

```ts
import sanitizeHtml from 'sanitize-html' // [!code --]
import { sanitize } from 'neosanitize' // [!code ++]

const clean = sanitize(dirty, {
allowedTags: ['b', 'i', 'em', 'strong', 'a'],
allowedAttributes: {
a: ['href']
}
})
```

Because it has no dependencies and runs anywhere, it works unchanged in browsers and edge runtimes:

```ts
import { sanitize } from 'neosanitize/browser'

const clean = sanitize(userInput)
```

Preset configurations are available under `neosanitize/presets`, and the underlying parser can be used directly via `neosanitize/whatwg-parser`.
16 changes: 16 additions & 0 deletions manifests/preferred.json
Original file line number Diff line number Diff line change
Expand Up @@ -2540,6 +2540,12 @@
"replacements": ["crypto.timingSafeEqual"],
"url": {"type": "e18e", "id": "buffer-equal-constant-time"}
},
"sanitize-html": {
"type": "module",
"moduleName": "sanitize-html",
"replacements": ["neosanitize/legacy", "neosanitize"],
"url": {"type": "e18e", "id": "sanitize-html"}
},
"scmp": {
"type": "module",
"moduleName": "scmp",
Expand Down Expand Up @@ -3364,6 +3370,16 @@
"type": "documented",
"replacementModule": "neoqs"
},
"neosanitize": {
"id": "neosanitize",
"type": "documented",
"replacementModule": "neosanitize"
},
"neosanitize/legacy": {
"id": "neosanitize/legacy",
"type": "documented",
"replacementModule": "neosanitize/legacy"
},
"neotraverse": {
"id": "neotraverse",
"type": "documented",
Expand Down
Loading