createRoot and the Root Container
The connection between the HTML document and App.jsx lives inside main.jsx. Open that file and name every value in the connection.
A client React application needs an existing DOM node. React DOM attaches a root to that node. The root receives React content and manages the container's descendants.
HTML creates a DOM container
main.jsx finds that container
createRoot attaches a React root
root.render supplies React contentThe four lines describe separate actions. Keeping them separate prevents the root container, the React root, and the application component from becoming one vague idea.
Find the Container in HTML
Open index.html at the project root. Its body contains an element close to this one.
<div id="root"></div>The browser parses the element before the module script runs. It creates a HTMLDivElement and stores root as the element's id.
The word root in that ID has no built-in React behavior. Another ID works too.
<main id="application"></main>React only needs a DOM node. The name becomes meaningful because main.jsx searches for the same ID.
An HTML ID identifies an element in the document. A React root is the object returned by createRoot. They are related values, not the same value.
The default Vite document also loads the client entry.
<script type="module" src="/src/main.jsx"></script>The browser encounters the module script, requests main.jsx through Vite, and evaluates its imports. By that time, the earlier div has been parsed and can be found through document.
Read main.jsx One Value at a Time
The generated entry is close to this form.
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.jsx";
import "./index.css";The imports make four names or effects available. StrictMode is a React development checking component. createRoot is the React DOM client function. App is the application component. The CSS import asks Vite to include document styles.
The entry then finds the DOM node.
const container = document.getElementById("root");document comes from the browser. getElementById returns the element whose ID matches, or null when no such element exists.
The next line creates a React root.
const root = createRoot(container);Finally, the root receives React content.
root.render(<App />);The variable names are local choices. These names communicate the two values clearly.
container holds a DOM node
root holds a React DOM root objectCheck the Container Before Calling React DOM
JavaScript allows container to be null. createRoot requires a DOM element.
The HTML and JavaScript can disagree after an ID edit.
<div id="application"></div>const container = document.getElementById("root");No element has the requested ID, so the lookup returns null. Passing that value to createRoot produces an error instead of a screen.
Make the requirement explicit.
const container = document.getElementById("root");
if (!container) {
throw new Error('Missing the DOM element with id="root"');
}Only create the root after the check.
const root = createRoot(container);
root.render(<App />);The error message names the exact missing requirement. A generic message such as Failed to start would force the reader to search for the condition.
Verify external values before passing them into an API that requires a narrower value. The DOM lookup can fail even when the source normally contains the element.
In TypeScript, this check also narrows the value from HTMLElement | null to HTMLElement for the remaining code.
createRoot Manages a Container
createRoot(container) tells React DOM that React will manage content inside this container. It returns a root with methods including render and unmount.
The function does not return the div.
const root = createRoot(container);root is not a DOM element, so browser element methods cannot be called on it.
root.appendChild(node);The DOM container still exists in container. React content is supplied through root.render.
Create one root for a container and retain it. Calling createRoot again on the same node is not a way to update the application.
const firstRoot = createRoot(container);
const secondRoot = createRoot(container);React reports a warning because a root is already attached to the container. Use the existing root for later renders.
root.render(<App />);Create the root once for a container. State updates normally cause later renders without another createRoot call.
The First root.render Call
root.render(<App />) requests React to display the supplied React node inside the root.
root.render(<App />);<App /> produces a React element description. React calls the component while calculating the tree, and React DOM commits the required DOM nodes.
If the root container already has child HTML, the first completed client render replaces the container's existing children with React's result.
<div id="root">
<p>Loading application</p>
</div>The paragraph can appear before JavaScript loads. After the first React render completes, React manages the children and the paragraph remains only if React output includes equivalent content.
This behavior is different from hydration. hydrateRoot attaches React to server-produced HTML that already matches the React output.
Do not use createRoot to attach to server-rendered React HTML that must be preserved. That case uses hydrateRoot and requires matching server and client output.
Render StrictMode Around the App
The Vite template normally supplies this root content.
root.render(
<StrictMode>
<App />
</StrictMode>,
);StrictMode enables additional development checks for the React tree inside it. These checks can run selected rendering work again and can repeat Effect setup in development. They expose component code that changes external data during rendering or omits cleanup.
Strict Mode has no visible DOM element. The browser DOM begins with whatever App returns.
It also does not make the production bundle render everything twice. The additional checks described here run in development.
Leave it in place. When a later log appears more than once, investigate whether the log sits in render-time code before removing the check.
Content Outside the Container Remains Outside the Root
React manages descendants inside its container. The surrounding document can remain ordinary HTML.
<body>
<header>ReactBook</header>
<div id="root"></div>
<footer>Copyright 2026</footer>
</body>Rendering App does not remove the header or footer because neither is a child of the root container.
The root can also render portals into another DOM node, but ordinary component output stays within the root's managed tree.
Application components should determine descendants of the root. A separate script should not replace those descendants after React has started.
More Than One Root
An existing page can contain two independent React regions.
<div id="reaction-controls"></div>
<div id="reading-progress"></div>Each region receives its own root.
const reactionsRoot = createRoot(reactionsContainer);
const progressRoot = createRoot(progressContainer);The roots can render different component trees.
reactionsRoot.render(<ReactionControls />);
progressRoot.render(<ReadingProgress />);This works for independent additions to an existing page. A full React application normally prefers one root so components can share state, context, routing, and error handling inside one tree.
Two roots do not create a parent-child React relationship merely because their DOM containers are near each other.
Context flows within one React tree. A provider rendered in one root does not supply context to a component rendered by another root.
Update the Existing Root
A root can receive another render call.
root.render(<App mode="reading" />);Later, the same root can receive another element.
root.render(<App mode="review" />);React compares the next tree with the current tree and preserves compatible component state. Application code rarely calls the top-level root.render for each interaction. State setters inside components request normal updates. The root remains the application entry point.
Changing the top-level component type changes the rendered tree.
root.render(<AdminApp />);React may remove the previous App instance and create AdminApp. A change in component type can end one component instance and start another.
Unmount the Root
Some pages remove a React region while the surrounding document remains active. Call unmount on the root before another system removes the container.
root.unmount();React removes the rendered DOM content and cleans up component resources in that tree, including subscriptions established through Effects.
The root cannot render again after it has been unmounted.
root.unmount();
root.render(<App />);React reports an error because that root has ended. Create another root if the same DOM container later begins a new React tree.
Do not unmount during ordinary navigation inside a React application. Routers and conditional rendering change components while the application root remains active.
Keep Root Code Small
The client entry should make its startup work visible.
const container = document.getElementById("root");
if (!container) {
throw new Error('Missing the DOM element with id="root"');
}
createRoot(container).render(
<StrictMode>
<App />
</StrictMode>,
);Using the returned root inline is valid when no later code needs unmount or another explicit render call. A named root is also valid and exposes the object for inspection.
Do not place application sections inside main.jsx merely because it runs first. App defines the application UI. The entry performs browser startup and root creation.
Inspect the Result in Two Panels
Open the browser Elements panel. Under div#root, you should see the h1 returned by App.
div#root
h1
My first React screenThe div came from index.html. The h1 came from the React render.
With React DevTools installed, the Components panel shows StrictMode behavior and App in the React tree. It does not replace the Elements panel; the two panels describe different structures.
Root Failure Check
Temporarily change the HTML ID to application while leaving the JavaScript lookup as root. Save and reload.
The custom error should report the missing element. Restore the ID and confirm the heading returns.
This controlled failure proves that the JavaScript does not locate the container by filename, tag order, or React convention. It uses the exact DOM lookup written in the entry.
Lesson Check
Point to four distinct values or sources in the running project.
index.html creates the DOM container
document.getElementById returns that container
createRoot returns the React root
root.render receives the React application elementSource Notes
- React DOM reference,
createRoot - React DOM reference,
hydrateRoot - React reference,
StrictMode - MDN,
Document.getElementById()