root.unmount()
Destroys a rendered React tree and detaches React from its container DOM node.
root.unmount()- Added in React 18.0.0
Return value
undefinedundefined.
Errors
Does not throw itself, but any root.render() call after it throws "Cannot update an unmounted root".
Changelog
- PHP 18.0.0Replaced ReactDOM.unmountComponentAtNode(container), which took the DOM node instead of a root object and returned a boolean.
root.unmount ends a root's life. React unmounts every component in the tree — running each effect's cleanup and every componentWillUnmount — empties the container, and removes the event handlers it attached. Whatever state that tree held is gone.
When to reach for it
- A non-React page removes a region that hosted a React widget. Without
unmount, timers, subscriptions and listeners inside that tree keep running against detached DOM. - Tests: unmounting between cases is what stops one test's effects leaking into the next.
- Micro-frontends or browser extensions, where a host application mounts and discards React islands as the user navigates.
What trips people up
A root is single-use. After unmount, calling render on that same root throws Cannot update an unmounted root. You may, however, call createRoot again on the same DOM node to start over — that is the supported way to recreate a widget.
Order matters too: unmount before you remove the container from the document, so cleanup functions still see the nodes they are undoing work on. And never call unmount while React is rendering or committing — from inside a render, or synchronously in an effect cleanup — or React warns; defer it with a microtask or timeout.
Example
When to use it
- Tearing down a React island when the surrounding non-React page navigates away
- Cleaning up between test cases so effects and timers do not leak
- Removing a browser-extension overlay injected into someone else's page
- Freeing subscriptions held by a widget that a dashboard has just closed
Frequently asked questions
How do I remove a React app from the page?
Call unmount() on the root object you got from createRoot or hydrateRoot. React runs every effect cleanup, empties the container, and removes its event listeners; the container element itself stays in the DOM for you to remove.
Can I call root.render after root.unmount?
No — it throws "Cannot update an unmounted root". Call createRoot on the same DOM node to get a fresh root, which is explicitly allowed once the previous root has been unmounted.
What replaced ReactDOM.unmountComponentAtNode?
root.unmount() replaced it in React 18. The old function took the container element and returned a boolean; the new method is called on the root object and returns undefined.
More examples
Mount and unmount an island from a non-React page
The module keeps the root in a variable so the page can tear it down later. Setting root back to null after unmount is deliberate: it makes an accidental unmountChat() call a no-op and makes it obvious that mountChat must build a new root rather than reusing the dead one.
import { createRoot } from "react-dom/client";
function Chat({ roomId }) {
return <div>Chat room {roomId}</div>;
}
let root = null;
export function mountChat(container, roomId) {
root = createRoot(container);
root.render(<Chat roomId={roomId} />);
}
export function unmountChat() {
// Effects inside Chat get their cleanup functions called here.
root?.unmount();
root = null;
}
// Later, remounting needs a brand new root:
// mountChat(document.getElementById("chat"), "general");What happens if you render after unmounting
The unmount empties the container, and the next render throws rather than silently doing nothing. Creating root2 on the same DOM node is legal because the previous root released it — this is the one case where calling createRoot twice on an element does not warn.
import { createRoot } from "react-dom/client";
function Hello() {
return <p>Hello</p>;
}
const container = document.getElementById("root");
const root = createRoot(container);
root.render(<Hello />);
root.unmount();
// container.innerHTML is now ""
try {
root.render(<Hello />);
} catch (error) {
console.log(error.message); // "Cannot update an unmounted root."
}
// Supported recovery: a new root on the same node.
const root2 = createRoot(container);
root2.render(<Hello />);Unmounting between tests
Wrapping the unmount in act flushes the cleanup functions of every effect in the tree before the assertion or the next test runs, so intervals and subscriptions do not survive into another case. Testing Library's render/cleanup helpers do exactly this internally.
import { act } from "react";
import { createRoot } from "react-dom/client";
function renderIsolated(ui) {
const container = document.createElement("div");
document.body.appendChild(container);
const root = createRoot(container);
act(() => root.render(ui));
return {
container,
cleanup() {
act(() => root.unmount());
container.remove();
},
};
}
test("greets the user", () => {
const { container, cleanup } = renderIsolated(<p>Hi Ada</p>);
expect(container.textContent).toBe("Hi Ada");
cleanup();
});
Discussion