document.write() Usage
Rewriting the entire page while someone is reading it — that's what document.write() does. There are much better ways to update the DOM.
What is this?
Imagine someone is reading a book, and you rip out the page they are on and replace it with completely different text — mid-sentence. That is what document.write() does. It injects HTML directly into the document stream, and if called after the page has finished loading, it wipes the entire page and replaces it with whatever you wrote. Even when called during loading, it blocks the HTML parser, forcing the browser to stop everything while it processes the injected content.
Why it matters
- For your visitors:
document.write()blocks the HTML parser, which means the browser cannot continue rendering the page until the write operation completes. If the written content includes external scripts, the delay compounds. Visitors see a blank or partially rendered page longer than necessary. In the worst case (called after load), the entire page disappears and is replaced — a catastrophic experience. - For your business: Google's Lighthouse explicitly flags
document.write()as a performance problem. Chrome actively intervenes on slow connections by blockingdocument.write()calls that inject external scripts, which means your code might silently break for visitors on mobile networks. Beyond performance,document.write()is a security risk — if the content being written comes from user input, it is an XSS vector. - The standard: Never use
document.write(). Usedocument.createElement(),element.textContent,element.append(), or framework-level DOM updates instead. There is no modern use case wheredocument.write()is the right answer.
// Create and insert elements properly
const banner = document.createElement("div");
banner.textContent = "Welcome back!";
banner.className = "welcome-banner";
document.getElementById("app").append(banner);// Blocks parser, can wipe the page, potential XSS
document.write("<div class='banner'>Welcome back!</div>");
// Even worse: writing a script tag
document.write('<script src="https://ads.example.com/ad.js"><\/script>');How to fix it
React / Next.js
In React, you should never need document.write() — React manages the DOM for you. But third-party scripts (especially ad scripts and legacy analytics) sometimes use it. Wrap them in Next.js Script component with lazy loading.
import Script from "next/script";
// If a third-party script uses document.write internally,
// load it lazily so it doesn't block rendering
<Script
src="https://legacy-analytics.example.com/tracker.js"
strategy="lazyOnload" // loads after page is fully interactive
/>;
// For dynamic content injection, use refs or state — never document.write
("use client");
import { useRef, useEffect } from "react";
function DynamicBanner({ message }: { message: string }) {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (ref.current) {
// Safe: using textContent, not innerHTML or document.write
ref.current.textContent = message;
}
}, [message]);
return <div ref={ref} className="banner" />;
}If you are migrating legacy code that uses document.write():
// BEFORE: legacy pattern
document.write(`<div id="widget">${widgetHTML}</div>`);
// AFTER: modern equivalent
const container = document.createElement("div");
container.id = "widget";
container.innerHTML = DOMPurify.sanitize(widgetHTML); // sanitize if from external source
document.body.append(container);Plain HTML
Replace every document.write() call with proper DOM methods.
<!-- BAD: document.write for loading scripts -->
<script>
document.write('<script src="https://cdn.example.com/lib.js"><\/script>');
</script>
<!-- GOOD: dynamically create script element -->
<script>
const script = document.createElement("script");
script.src = "https://cdn.example.com/lib.js";
script.async = true;
document.head.appendChild(script);
</script>
<!-- BAD: document.write for dynamic content -->
<script>
document.write("<p>Today is " + new Date().toLocaleDateString() + "</p>");
</script>
<!-- GOOD: update existing element -->
<p id="date-display"></p>
<script>
document.getElementById("date-display").textContent =
"Today is " + new Date().toLocaleDateString();
</script>document.write() is a relic from the 1990s web. The cat does not tolerate outdated patterns that
hurt both performance and security. Modernize your DOM updates.
How the cat scores this
The scanner searches your JavaScript for calls to document.write() and document.writeln(). Each occurrence is flagged with its context — whether it is injecting scripts, HTML content, or dynamic values. Calls that inject external scripts receive a higher severity because they compound the performance impact. The scanner also checks whether the content being written includes any dynamic or user-controllable values, which would elevate the finding to a security issue (potential XSS).
Further reading
- web.dev: document.write() — why Lighthouse flags this
- MDN: document.write() — the docs (which themselves warn against using it)
- Chrome intervention — Chrome's blocking of document.write on slow connections
Insecure Dependencies
Building your house with recalled materials — that's what happens when your npm packages have known vulnerabilities. Audit and update them.
Sensitive Data in localStorage
Sticky note with passwords on your monitor — that's what storing secrets in localStorage looks like. Anyone who walks by can read them.