Let AI write emails and messages for you 🔥

Render React element inside shadow DOM in React v18

Gourav Goyal

Gourav Goyal

Nov 30, 2022

Suppose we want to render a React element (i.e., a button) after an existing element (i.e., an input box) in HTML. There are 2 ways to go about it. The first is without the shadow DOM approach, and the second is with shadow DOM. In both cases, we will use the official ReactDOMClient library and its createRoot method.

Install ReactDOMClient library if not already:

npm i react-dom/client

Render React element without shadow DOM

Let’s render a button element via React next to an existing input element in HTML:

Javascript / Typescript code:

import { createRoot } from "react-dom/client";

// create root container where react element will be inserted
let container = document.createElement("div");
container.classList.add("react-container")

// create react element
const reactButton = <button>Submit</button>;

// get hold of an existing element in HTML DOM
const domElement = document.getElementById("name");

// insert root container element in HTML DOM after the existing element
domElement.after(container);

// container as react root
const root = createRoot(container);

// render react element inside the container
root.render(reactButton);

HTML DOM before rendering the react element:

<body>
    <label for="name">Name:</label>
    <input type="text" id="name" name="name">
</body>

HTML DOM after rendering the react element:

notice the new div with react-container class

<body>
    <label for="name">Name:</label>
    <input type="text" id="name" name="name">
    <div class="react-container">
        <button>Submit</button>
    </div>
</body>

Note: any styles applied to the page will also be applied to the elements rendered by React, i.e., Submit button will inherit styles from the page CSS.

Render React element with shadow DOM approach

What’s a shadow DOM?

It’s a separate and isolated DOM for an element. It’s used to keep the markup structure, style, and behavior hidden and separated from other code on the page so that different parts do not clash and the code can be kept nice and clean.

shadow DOM
shadow DOM

Read more about shadow DOM:

Why should one use the shadow DOM approach in React?

If you render React element(s) inside a shadow DOM, the React element(s) won’t inherit any styles from the page CSS. For example, a third-party plugin that overlays some UI on top of a page would use a shadow DOM to prevent its UI from being affected by any page style.

Styling shadow DOM elements:

You can apply styling to shadow DOM elements by creating a style element or linking a css file.

To apply styling at runtime to shadow DOM element:

const shadowRoot = document.querySelector(".react-container").shadowRoot;
const button = shadowRoot.querySelector('div[role="button"');
button.style.display = "none";

Adding Tailwind support to shadow DOM:

Refer my other article: Add Tailwind styles to shadow DOM (gourav.io)

Now, Let’s render a button element via React next to an existing input element in HTML:

Javascript / Typescript code:

import { createRoot } from "react-dom/client";

// create root container where react element will be inserted
let container = document.createElement("div");
container.classList.add("react-container");

// attach shadow DOM to container
const shadowRoot = container.attachShadow({ mode: "open" });

// create react element
const reactButton = <button>Submit</button>;

// get hold of an existing element in HTML DOM
const domElement = document.getElementById("name");

// insert root container element in HTML DOM after the existing element
domElement.after(container);

// shadow DOM as react root
const root = createRoot(shadowRoot);

// render react element inside shadow DOM
root.render(reactButton);

HTML DOM before rendering the React element:

<body>
    <label for="name">Name:</label>
    <input type="text" id="name" name="name">
</body>

HTML DOM after rendering the React element:

notice the new div with react-container class and shadow-root

That's all, folks!
Hiring React Devs (in IST timezone) for my AI Startup.

Gourav's Newsletter
I write about startups, tech, productivity, personal development, and more.
Gourav Goyal

Gourav Goyal