Engrain by ByteRush

WEB.02.02 Mid-level· 11 minCore — asked often

Efficient DOM updates: adding 10,000 rows without freezing the page

Batch DOM changes, build off-screen with DocumentFragment and template cloning, swap content with replaceChildren, know innerHTML's cost and risk, and skip off-screen work with virtualization and content-visibility.

Comes up in: Web fundamentals, Machine coding

Learn#

Vivek’s admin table adds 10,000 orders with tbody.innerHTML += row in a loop. The tab freezes for 8 seconds. Each += turns the whole table back into a string, parses it again, and rebuilds every row.

Batching means making all your DOM changes together, in as few operations as possible, with no reads of layout in between (WEB.01.04).

A DocumentFragment is a lightweight container that is not in the page. Build there, then insert once:

const list = document.createElement("ul");
const names = ["Asha", "Ravi", "<b>Meera</b>"];
const fragment = document.createDocumentFragment();
for (const name of names) {
  const li = document.createElement("li");
  li.textContent = name; // text, never HTML
  fragment.append(li);
}
list.replaceChildren(fragment);
console.log(list.children.length, fragment.childNodes.length);
console.log(list.lastElementChild.innerHTML);

Output (verified)

3 0
&lt;b&gt;Meera&lt;/b&gt;

textContent kept the <b> as text, so a name cannot inject HTML.

replaceChildren removes the old children and inserts the new ones in one call.

Building off-page, inserting onceStep 1 of 4

Page

  • fragment: li × 3 (off-page)

State

    empty

    Build every row inside a DocumentFragment. It is not in the page, so nothing is styled or laid out yet.

    Read the steps as text
    1. Build every row inside a DocumentFragment. It is not in the page, so nothing is styled or laid out yet.
    2. One call, list.replaceChildren(fragment), removes the old rows and inserts all new ones at once.
    3. The fragment is now empty: its children moved into the list.
    4. The browser styles and lays out once, before the next frame.

    Predict#

    Predict first

    You append 1,000 elements to a list one by one in a single loop, with no reads in between. How many layouts run?

    Interview angle#

    Say it like this — about 30 seconds

    “To add many elements, I build them off-page, in a DocumentFragment or by cloning a template, and insert once, for example with replaceChildren. I never read layout in the middle. I avoid innerHTML += in loops, because it reparses everything and drops listeners, and innerHTML with user data is an XSS risk. For really large lists I render only the visible rows with virtualization, and content-visibility auto lets the browser skip rendering off-screen sections.”

    Stays on your device. Nothing is uploaded.
    Follow-up How would you add 1,000 elements to the DOM efficiently?
    Create them in a DocumentFragment (or clone a template), then append once; avoid layout reads during the loop.
    Follow-up What does content-visibility: auto do?
    It lets the browser skip style, layout and paint for an off-screen element until it comes near the viewport. Give it contain-intrinsic-size to keep the scroll height.
    Follow-up Why is innerHTML risky?
    It parses strings as HTML, so user data can run scripts (XSS), and replacing it destroys existing nodes and their listeners.

    Practice#

    Guided

    Replace the slow, unsafe innerHTML += loop with a safe single update.

    Done when

    • Each row becomes a <tr> with two <td>s, and old rows are removed.
    • Names containing HTML show as plain text; no element is created from them.
    • All rows are added with one operation on tbody.
    Your solution
    Ctrl/⌘ + Enter

    Remember#

    Try to answer each card before you open it. Then add them to your reviews.

    What is a DocumentFragment?

    An off-page container for nodes; appending it moves its children in one operation.

    Why is innerHTML += in a loop slow?

    Each time it serializes and reparses everything already there.

    What does content-visibility: auto do?

    Skips rendering work for off-screen content until it nears the viewport.

    What is list virtualization?

    Rendering only the rows near the viewport, and reusing them while scrolling.

    Go deeper

    Four layers. Stop at the one your interview needs; each ends with a quick check.

    The core ideaEvery round

    el.replaceChildren(...nodes) clears and fills in one call; with no arguments it empties the element. append accepts many nodes and strings at once, too.

    Check yourself: What does replaceChildren() with no arguments do?

    Removes every child.

    How it works underneathSenior rounds
    A <template> is parsed once and never rendered. template.content.cloneNode(true) copies a ready-made subtree, which is quick for rows with many elements. Fill the clone with textContent.
    Check yourself: Why clone a template instead of building each row with createElement?

    The template is parsed once; cloning a ready subtree is cheap.

    Edge cases and trapsWhere people slip

    innerHTML is fast for one big static insert, but it parses strings as HTML: user data can become <img onerror> (QLT.05.02). Replacing it destroys existing nodes, focus and listeners.
    setHTML() with the Sanitizer API is the safer future option.

    Check yourself: What two problems does innerHTML create?

    XSS when it includes user data, and lost nodes and listeners when it replaces content.

    In productionStaff-level answers
    For thousands of rows, render only what is visible (virtualization, MC.04).
    Virtualization works with any framework; content-visibility: auto is a CSS-only middle ground (Chrome 85, Firefox 125, Safari 26) Source: web.dev: content-visibility Source: MDN: Element.replaceChildren().
    Check yourself: What must you set with content-visibility: auto to avoid scroll jumps?

    contain-intrinsic-size, an estimated size for skipped content.

    Finished the five steps? Mark it, and its cards join your reviews.

    Last checked 2026-11-01. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.

    Interview questions this answers

    • How would you add 1,000 elements to the DOM efficiently?
    • What does content-visibility: auto do?