HTMLRewriter (lol-html)

htmlRewrite applies declarative rules to HTML right in the server-render path. The native lol-html engine (the same streaming rewriter behind Bun's HTMLRewriter) walks the document once and applies each action by CSS selector — no virtual DOM, no tree to parse, and no per-element JavaScript callback. Perfect for injecting a CSP nonce, rewriting URLs to a CDN, hardening external links, or injecting fragments — all at streaming speed.

Tip
A few real use cases, all shown below: CSP nonces — set a nonce attribute on every <script> for a strict Content-Security-Policy; CDN rewriting — prefix every relative src / href with your CDN origin; hardening — add rel="noopener noreferrer" to every target="_blank" (anti tabnabbing); and fragment injection (banners, comments, analytics tags) without touching the rest of the markup.

Input

input.htmlHTML
<div><img src="/hero.png"><a href="https://ext.com" target="_blank">ext</a><script>x()</script></div>

Rules

src/app/examples/html-rewriter/page.tsxTypeScript
import { htmlRewrite, type HtmlRule } from "@bext-stack/framework";

const input =
  `<div><img src="/hero.png"><a href="https://ext.com" target="_blank">ext</a><script>x()</script></div>`;

const rules: HtmlRule[] = [
  { selector: "img[src]",         prefixAttribute: ["src", "https://cdn.example.com"] },
  { selector: "a[target=_blank]", setAttribute:    ["rel", "noopener noreferrer"] },
  { selector: "script",           setAttribute:    ["nonce", "DEMO123"] },
  { selector: "div",              appendHtml:      "<!-- rewritten by bext HTMLRewriter -->" },
];

// Runs natively at SSR via the lol-html bridge (__htmlRewrite).
const output = htmlRewrite(input, rules);

Output (rewritten natively at render)

output.htmlHTML
<div><img src="https://cdn.example.com/hero.png"><a href="https://ext.com" target="_blank" rel="noopener noreferrer">ext</a><script nonce="DEMO123">x()</script><!-- rewritten by bext HTMLRewriter --></div>