Overview
React renders custom elements as generic HTML, which means it passes all props as attributes (strings) and cannot bind to custom event names.@lit/react bridges this gap with two utilities:
createComponent— wraps a web component class in a ReactforwardRefcomponent that sets element properties directly and maps React prop names to DOM events.useController— turns a LitReactiveControllerinto a React hook.
Installation
react must also be installed (any React 16.8+ version with hooks).
createComponent()
createComponent returns a typed React component backed by your custom element.
Signature
Parameters
react
react
Pass the
React module you import in your project. This avoids bundling conflicts when React is loaded in multiple ways.tagName
tagName
The tag name your element is registered with via
customElements.define. Must match exactly.elementClass
elementClass
The custom element class.
createComponent inspects its prototype to identify which React props should be set as element properties rather than HTML attributes.events
events
An object mapping React prop names (e.g.
onActivate) to the DOM event names your element dispatches (e.g. 'activate'). Functions passed via these props are wired to the element as event listeners.displayName
displayName
Optional label for React DevTools. Defaults to the element class name.
Complete example
TypeScript types
@lit/react exports several types for TypeScript users:
| Type | Description |
|---|---|
EventName<T extends Event> | Brands a string as carrying a specific event type; use it in the events map to type-narrow event callbacks |
ReactWebComponent<I, E> | The return type of createComponent |
WebComponentProps<I> | Props type for using a web component directly in JSX without createComponent |
Typed events with EventName
WithoutEventName, event callbacks receive the base Event type. Cast the event name to get the precise type:
useController()
useController converts a Lit ReactiveController into a React hook, driving the full controller lifecycle from React’s own hooks.
| Controller lifecycle | React equivalent |
|---|---|
constructor / hostConnected | useState initial value |
hostDisconnected | useLayoutEffect cleanup (empty deps) |
hostUpdate | Hook body (runs every render) |
hostUpdated | useLayoutEffect |
requestUpdate | useState setter |
Server-side rendering and Next.js
Custom elements cannot execute in a Node.js SSR environment.createComponent uses useLayoutEffect internally, which React suppresses during server rendering, so the component renders as an empty tag on the server and hydrates on the client.
For full SSR support (including server-rendered shadow DOM), use
@lit/ssr-react together with @lit/react. The createComponent wrapper passes element properties via a special _$litProps$ bag when @lit/ssr-react’s patched createElement is detected.Next.js setup
Mark wrapper components with'use client' so Next.js treats them as client components and does not attempt to server-render the web component: