hast-util-to-html

Serializes hast syntax trees into WHATWG-compliant HTML strings, with fine-grained control over escaping, quoting, and tag omission.

Library
npm
v9.0.5
118 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
43 /100 Fair
Development Activity 0
Maintenance 32
Community 68
Maturity 60
Momentum 12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
74 /100 Good
Architecture 85
Code Quality 92
Innovation 55
Learning Curve 65

hast-util-to-html is the canonical HTML serializer for the unified/hast ecosystem, turning a hast syntax tree back into a WHATWG-compliant HTML string. It underlies rehype-stringify, the terminal stringifier used by nearly every rehype and remark-to-HTML pipeline, which is why it sits at extremely high npm download volume despite a small, focused API surface.

Beyond straightforward serialization, it exposes a large set of formatting options — omitting optional tags, tightening attribute whitespace, smart-quoting, self-closing SVG elements, and configuring character-reference encoding — so the same tree can be rendered as readable markup for humans or minified output for production bundles, all while automatically toggling between HTML and SVG serialization rules as it walks the tree.

What You Get

  • A single toHtml(tree, options) export with no default export, fully typed via JSDoc-derived TypeScript declarations
  • Automatic HTML/SVG namespace switching when the tree crosses an <svg> boundary, so attribute casing and void-element rules stay correct
  • Over a dozen formatting knobs (quoting, tag omission, tight attributes, doctype casing) for producing either readable or byte-minimal output
  • Configurable character-reference and XSS-safety controls (allowDangerousHtml, allowDangerousCharacters) that default to safe encoding unless explicitly disabled

Common Use Cases

  • Serializing a processed hast tree back to HTML at the end of a rehype pipeline, typically via rehype-stringify
  • Building HTML minifiers or pretty-printers on top of hast by toggling the tight/omission options
  • Round-tripping HTML through hast-util-from-html → transform → hast-util-to-html
  • Re-emitting sanitized (via hast-util-sanitize) user content back to safe HTML strings

Under The Hood

Architecture The library is a thin dispatch layer over a zwitch-based visitor: lib/handle/index.js builds a zwitch('type', ...) switch keyed on hast node type (comment, doctype, element, raw, root, text), each handled by its own small file in lib/handle/. lib/index.js owns the public toHtml() entry point, builds a shared State object (settings, current quote/alternative quote, active schema from property-information) and exposes one/all recursion helpers that the individual handlers call back into; lib/handle/element.js is the largest handler (~265 lines) because it owns attribute serialization, self-closing/void-element logic, and the HTML↔SVG schema swap on <svg> boundaries. Optional-tag omission is fully isolated into lib/omission/ (opening.js, closing.js, omission.js), which element.js consults only when omitOptionalTags is set — a clean separation between “always correct” serialization and “legal but aggressive” minification behavior.

Tech Stack Plain ESM JavaScript ("type": "module") with zero build step for runtime — types ship via a tsc --build pass emitting .d.ts/.d.ts.map declaration files from JSDoc comments, checked with type-coverage (configured for 100% strict coverage in package.json). Runtime dependencies are all narrowly-scoped unified-ecosystem utilities: property-information (attribute/schema knowledge), stringify-entities (character-reference encoding), zwitch (type-based dispatch), plus small helpers (ccount, comma-separated-tokens, space-separated-tokens, html-void-elements, hast-util-whitespace). Linting/formatting run through xo (ESLint config) and prettier; CI (.github/workflows/main.yml) runs the test suite across two Node LTS lines and uploads coverage to Codecov.

Code Quality Testing is extensive and enforced strictly: test/ contains 30+ files, with dedicated suites per node type (element.js, comment.js, doctype.js, text.js, raw.js, root.js) plus an entire subset (omission-*.js, 20+ files) exercising every individual optional-tag-omission rule (e.g. omission-closing-tbody.js, omission-opening-html.js) and a dedicated security.js suite for XSS-relevant escaping behavior. The test npm script chains build (typecheck + type-coverage) → format (remark/prettier/xo —fix) → test-coverage, and test-coverage runs c8 --100, meaning the project fails CI on anything less than 100% statement coverage. This is a notably higher bar than most npm packages in this size class.

API Design The public surface is intentionally minimal — one function, one options object, no classes or default export — which keeps the getting-started cost close to zero (import {toHtml} from 'hast-util-to-html'; toHtml(tree)). Every option is documented inline via JSDoc @property tags with defaults spelled out, and the README mirrors that same structure field-by-field, so IDE tooltips and the docs site stay in lockstep. The main ergonomic cost is the sheer number of formatting options (15+), most of which exist purely to support minifier/pretty-printer use cases rather than everyday serialization, but sensible false defaults mean the common case needs no configuration at all.

Used by 8 apps in this directory

Go
62%
Apache 2.0

Harness Open Source

Code Editors · Developer Tools · Devops

38,450

A unified open source DevOps platform combining Git hosting, CI/CD pipelines, cloud development environments, and artifact registries in a single self-hosted system.

View details
89
Repo Health
79
Technical
64
Dependency
Built with
Go 62%
TypeScript 33%
Updated 2 weeks ago
Go
56%
Other

Multica

AI Assistants · AI Development

51,481

Turn coding agents into real teammates — assign issues, track progress, and compound reusable skills across a vendor-neutral, self-hosted platform.

View details
87
Repo Health
83
Technical
67
Dependency
Built with
Go 56%
TypeScript 38%
Updated 1 weeks ago
Go
74%
Other

Notifuse

Marketing

2,223

Open-source, self-hosted alternative to Mailchimp, Brevo, and Klaviyo — send newsletters and transactional emails without per-email pricing or vendor lock-in.

View details
81
Repo Health
80
Technical
66
Dependency
Built with
Go 74%
TypeScript 23%
Updated 3 weeks ago
TypeScript
98%
Other

Novu

Developer Tools

40,084

Open-source communication infrastructure that connects your products and AI agents to every channel your users live on — Inbox, Email, SMS, Push, Chat, and more.

View details
93
Repo Health
80
Technical
64
Dependency
Built with
TypeScript 98%
Updated 1 weeks ago
TypeScript
98%
Other

Orama

Developer Tools · Search

10,565

A complete, embeddable search engine and RAG pipeline running in browsers, servers, and edge networks with full-text, vector, and hybrid search in under 2KB.

View details
68
Repo Health
83
Technical
64
Dependency
Built with
TypeScript 98%
Updated 4 weeks ago
Python
55%
Other

PostHog

Ab Testing Experimentation · Analytics · Developer Tools

39,975

The all-in-one open source product platform combining analytics, session replay, feature flags, error tracking, AI observability, and a built-in data warehouse in a single self-hostable stack.

View details
92
Repo Health
80
Technical
65
Dependency
Built with
Python 55%
TypeScript 36%
Updated 1 weeks ago
TypeScript
72%
Apache 2.0

Supabase

Authentication · Databases · Developer Tools

110,828

The open-source Postgres development platform that replaces Firebase with authentication, real-time APIs, edge functions, storage, and vector embeddings — all built on PostgreSQL.

View details
90
Repo Health
91
Technical
62
Dependency
Built with
TypeScript 72%
MDX 26%
Updated 1 weeks ago
Python
57%
Apache 2.0

Zulip

Team Chat

25,962

Topic-based team chat that brings the structure of email threads to real-time messaging, so distributed teams never lose context across hundreds of concurrent conversations.

View details
96
Repo Health
86
Technical
61
Dependency
Built with
Python 57%
TypeScript 19%
JavaScript 10%
Updated 1 weeks ago

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