React components are great — until you want to use them outside a React application.
Maybe you want to:
- embed a widget in a static site
- integrate React UI into a legacy app
- expose components in plain HTML
In those situations, Web Components are the universal interface.
In this article, I’ll show how to wrap a React component as a custom element that works anywhere — and how a small library makes it trivial.
👉 Library used in this article: Elementizer
The Problem
A React component normally requires a React environment:
import { createRoot } from "react-dom/client";
import MyComponent from "./MyComponent";
createRoot(document.getElementById("app")).render(<MyComponent />);
This means:
- React must control the rendering
- the host app must use React
- integration becomes complex
What we really want is something like this:
<my-component message="Hello world"></my-component>
That’s exactly what Web Components provide.
The Idea
The goal is simple:
- Take a React component
- Wrap it inside a Custom Element
- Let React render inside the element
Then the component becomes framework-agnostic.
However, it's worth mentioning that React and Web components are strongly incompatible, and every difference is subject to making things go wrong:
- their architecture is different
- the component life-cycle is different
- the state management is different
- refreshing the rendering is different
Tools like Elementizer make the process extremely lightweight.
If you’ve ever wanted to ship React components that work everywhere, this approach is worth trying.
Out-of-the-box :
✅ Automatic attribute conversion
✅ Automatic event handling
✅ Support of child nodes
✅ Support of React contexts
For more complex cases :
✅ Custom attribute mappers
✅ Custom event mapper
✅ Custom context filling
✅ Custom rendering
A Simple React Component
Let’s start with a small React component.
export function Hello({ name }) {
return <h2>Hello {name} 👋</h2>;
}
Normally you would render it with React.
But instead, we want to expose it as:
<hello-user name="Alice"></hello-user>
Turning It into a Web Component
Using Elementizer, you can register the component as a custom element in one step.
import { createElement } from '@badcafe/elementizer';
import { Hello } from './Hello';
createElement({
name: 'hello-user',
reactComponent: Hello
});
That’s it.
Now the browser understands:
<hello-user name="Alice"></hello-user>
And React renders inside the element.
How it works
Unlike a React app where the React tree is superposed to the DOM tree, Elementizer manages a React tree separated from the DOM tree, which makes possible the cohabitation of React with non-React components; the link between the 2 worlds is made with portals and observers:
- The React tree is made exclusively of React portals
- React portals are rendered in the HTML tree
- Observers let React components re-render when their Web component wrapper is updated
Try It Yourself
You can explore the project and examples here: https://badcafe.github.io/elementizer/
Source code: https://github.com/badcafe/elementizer/tree/main/lib
Top comments (0)