Skip to main content
Nitro Modules · Lexbor · QuickJS

A headless DOM sandbox
for React Native

A headless HTML/DOM environment for React Native, powered by Nitro Modules, Lexbor, and QuickJS.

sandbox.ts
import { JSDOM } from 'react-native-nitro-jsdom'

const dom = JSDOM.create(`
<html>
<body>
<div id="result">0</div>
</body>
</html>
`)

await dom.evaluate(`
document.getElementById('result').textContent = String(2 + 2)
`)

const value = await dom.evaluate(
`document.getElementById('result').textContent`
)
// → "4"

dom.dispose()
Why this library

Everything a WebView gives you, none of the baggage

Headless & off-tree

No React component, no screen, no UI tree. Parse, mutate, and evaluate HTML entirely off-screen.

Truly isolated runtime

Every JSDOM.create() spins up its own QuickJS runtime, not a shared Hermes instance. No leaking globals between sandboxes.

Native HTML parsing

Backed by Lexbor, the fastest WHATWG-compliant HTML parser in C99, with zero dependencies.

jsdom-shaped DOM API

querySelector, textContent, dataset, and more mirror jsdom's DOM shape, though usage differs: everything runs through the async evaluate(), not jsdom's synchronous object access.

Synchronous JSI bridge

Powered by Nitro Modules, with direct JSI calls, no bridge, no JSON serialization overhead.

Full memory control

Call dispose() to deterministically free the Lexbor document and QuickJS runtime, no waiting on GC.

Under the hood

One synchronous call, two native engines

evaluate() is the only door into the sandbox: everything else happens natively, off the JS bridge.

TypeScript (consumer)
synchronous JSI call, no bridge, no JSON
Nitro Module (C++ binding layer)
Lexbor (C99)
  • WHATWG-compliant HTML parsing
  • In-memory DOM tree
  • querySelector / querySelectorAll
  • serialize() → HTML string
QuickJS (C)
  • Isolated JS runtime per instance
  • DOM bindings → delegates to Lexbor
  • setTimeout / setInterval, own event loop
  • Executes arbitrary user scripts
The alternative

Why not just use a hidden WebView?

FeatureWebView (hidden)react-native-nitro-jsdom
Requires a React component
Runs headless / off-tree
Isolated instancesComplexNative
Arbitrary JS execution
Full DOM APIProgressive
Memory controlLimitedFull (dispose())
Performance overheadHighLow

Ready to sandbox your first DOM?

Install the library and run your first evaluate() in minutes.