Library / SDK
capricorn86/happy-dom avatar
capricorn86/happy-dom

happy-dom: the browser you can hand to a unit test in milliseconds

A JavaScript implementation of a web browser without its graphical user interface

4,692 stars344 forksTypeScriptMIT

At a glance

What is it?
A headless DOM implementation in TypeScript that boots fast enough to sit under every Jest or Vitest suite, and a repository that shows exactly how much of the browser it leaves out.
Who is it for?
happy-dom is built for one job: making a component render in a test process without launching anything. It gets there by implementing the parts of the DOM that components actually touch and skipping the parts that need a real engine, which is why its feature list fits in five bullets and why it sits next to Vitest, Bun, Jest and Testing Library rather than beside Playwright.
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 27 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 7, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Five implemented features and a much longer list of integrations

The README describes happy-dom in one sentence: a JavaScript implementation of a web browser without its graphical user interface. That is the whole pitch. It is not a browser, it does not render pixels, and it does not ship a JavaScript engine. It is the DOM layer that sits between your component code and a browser, rebuilt in JavaScript so it can start inside a Node process without the cost of a browser process.

The DOM feature list is strikingly short. Custom Elements, meaning web components. Declarative Shadow DOM. Mutation Observer. Tree Walker. Fetch API. Then And much more, which is where the README stops.

What follows is a Works With list, and it is longer than the feature list: Vitest, Bun, Jest, Testing Library, Google LitElement, Vue, React, Svelte and Angular. Read that as the actual specification of the project. The goal is not to be a browser. The goal is that whatever test runner and component library you already have can be pointed at something faster than jsdom without changing how your tests are written. The repository topics say the same thing from the other side, listing jest, vitest, testing-library, bun, angular, react, vue, svelte, lit-element and lit-html alongside the more technical dom, whatwg and web-components.

The license is MIT, held by David Ortner, and the copyright line runs from 2019 to the present, which dates the project's start.

A turbo monorepo where the tests are the specification

The root `package.json` is more revealing than the README about how this project is run. It is a private root named root, pinned to npm 10.9.2 as its package manager, with three workspace globs: `packages/*`, `packages/@happy-dom/*` and `integration-test/*`. So happy-dom is not one package but a monorepo with an integration test project living alongside the published crates.

Every task is delegated to turbo, which is how a repository of this size keeps builds honest.

json
"scripts": {
	"compile": "DO_NOT_TRACK=1 turbo run compile",
	"test": "DO_NOT_TRACK=1 turbo run test && turbo run test:circular-dependencies",
	"lint": "eslint --max-warnings 0 --cache --cache-location ./.turbo/eslint.turbo ."
}

Two details in that snippet are worth pausing on. The test script runs a second pass called `test:circular-dependencies`, which for a project full of interdependent DOM classes is exactly the check you would want and rarely see. And the lint script passes `--max-warnings 0`, so warnings are failures rather than advice.

The toolchain is pinned tightly: TypeScript 5.8.3, vitest 4.1.8, eslint 8.56 with a plugin per concern, prettier 3.3.3, husky 9.0.6, and a `happy-conventional-commit` dependency, which means commit messages are checked against a convention. `node >=20.0.0` is the stated engine requirement, in both `engines` and the `@types/node` range. The root also sets `prepare: husky`, so a clone installs its own git hooks.

What the parser was doing in September 2026

The three most recent releases are all patch releases, all from the same contributor, and all about the HTML parser rather than the API surface. v20.14.3 on 2026-09-09 avoids cloning all properties in `CSSPropertyManager.toString`, credited to @erictheswift. v20.14.4 on 2026-09-12 ends comments at the first comment end tag when it overlaps a comment start tag. v20.14.5 the same day preserves character references in comment data. Both of the September 12 fixes come from @hampustagerud and reference tasks #2407 and #2409.

Read together, those three commits describe a serializer and parser being hardened against malformed or unusual markup. Cloning all properties on every `toString` call is a performance bug, and overlapping comment delimiters is a parser correctness bug that shows up the moment a test asserts on comment content. Neither is glamorous, and both are the kind of thing that only surfaces when a lot of people run the thing in CI.

The version numbering is also a signal. A project at v20 with patch releases on consecutive days is one that ships continuously and does not batch changes. The practical consequence for you as a user is that pinning a version is more meaningful than usual, because what you get on Monday may differ from what you got on Friday.

Repository scale: 4,661 stars and 459 open issues

The repository has 4,661 stars, 328 forks and 459 open issues, with the last push on 2026-09-12 and no archive flag. That issue count is worth staring at rather than glossing over. For comparison, a project with a quarter of the stars usually has an issue count you would call backlog; 459 open issues on 4,661 stars points to a project that is genuinely used at scale by people filing real gaps against it.

Some of that is by design. The topic tags include hacktoberfest and hacktoberfest2025, so a meaningful fraction of the incoming issues are probably first-time contributions from an annual event. That is healthy for a project whose subject is enumerable, since implementing another corner of the HTML specification is a well-scoped task, and it explains the steady patch cadence.

The repository layout follows from the same logic. Alongside the source there are `docs/`, `integration-test/`, `turbo.json`, a `cspell.json` for spell checking, `.eslintrc.cjs` and `.prettierrc.cjs`, a `CODE_OF_CONDUCT.md`, a `CONTRIBUTING.md` and a `SECURITY.md`. There is no examples directory and no in-repository documentation of the API itself, which is the single largest gap in the project as far as a new user is concerned.

The last push date is 2026-09-12, and the current version is v20.14.5, so this is not a project in maintenance mode.

Documentation lives in the wiki, not in the repository

The README links exactly three documentation targets and all three are GitHub wiki pages rather than files you can read offline: Documentation, Getting started, and Setup as Test Environment. Then it says complete documentation lives at the wiki and points contributing to `CONTRIBUTING.md` in the repo.

That split has a practical consequence. If you clone the repository you get the source, the tests, and no manual. Everything you need to evaluate whether happy-dom will work for your setup is behind a wiki link, which means it will not show up in a code search and will not tell you which version it describes. Wiki pages also tend to rot more quietly than versioned docs in a `docs/` folder, and this repository does have a `docs/` directory that appears to hold images rather than guides, since the README pulls its logo from `docs/happy-dom-logo.jpg`.

For a project at this size, that is the honest trade. Writing a complete guide for Custom Elements, Declarative Shadow DOM, Mutation Observer, Tree Walker and Fetch would be a documentation project in its own right, and a contributor-maintained wiki gets more of it written than a single author would finish. It just means you should budget an extra hour for Setup as Test Environment before you budget an afternoon for the API.

The distinction that matters most when you read it is between the DOM and the runtime. happy-dom gives you nodes, elements, attributes, observers and a fetch shim. It does not give you layout, it does not give you a JavaScript engine's profiler, and it does not give you a real compositor. Anything that depends on measuring a box is a different problem.

Editorial conclusion

happy-dom is built for one job: making a component render in a test process without launching anything. It gets there by implementing the parts of the DOM that components actually touch and skipping the parts that need a real engine, which is why its feature list fits in five bullets and why it sits next to Vitest, Bun, Jest and Testing Library rather than beside Playwright. Three patch releases landed inside three days in September 2026, all fixing HTML parser edge cases around comment nodes, which tells you both that the parser is still being hardened and that the maintainer ships continuously. The honest starting point is the repository's own wiki, which is where the Getting started and Setup as Test Environment pages live, with the source in `packages/` as the reference for what a given API actually does.

Frequently asked questions

What are some alternatives to JSDOM?

On the Node side, happy-dom is the one most directly comparable: a JavaScript implementation of a browser DOM that starts faster, and the README lists Vitest, Bun, Jest and Testing Library among the tools it works with. The other alternative is to stop mocking the DOM at all and drive a real browser with Playwright, which is slower per test but runs the code you actually ship.

Is happy-dom a real browser?

No. The README calls it a JavaScript implementation of a web browser without its graphical user interface, and it implements the DOM layer rather than an engine. That means nodes, elements, Custom Elements, Declarative Shadow DOM, Mutation Observer, Tree Walker and a Fetch API, but not layout, rendering or a JavaScript engine.

How do I set up happy-dom as a test environment?

The repository README points at a wiki page called Setup as Test Environment, alongside Getting started. Those wiki pages hold the configuration detail for wiring the DOM into a runner, which is not documented in files inside the repository itself.

Does happy-dom support custom elements and web components?

Yes, Custom Elements are the first item on the README's DOM feature list, alongside Declarative Shadow DOM. LitElement and lit-html are named in the Works With list, and web-components is one of the repository topics, so component libraries built on the custom element registry are the intended audience.

Official sources

  1. capricorn86/happy-dom on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
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/capricorn86-happy-dom.svg)](https://hysenlabs.com/projects/capricorn86-happy-dom)