or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-lit--react

A React component wrapper for web components and React hooks for Reactive Controllers.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@lit/react@1.0.x

To install, run

npx @tessl/cli install tessl/npm-lit--react@1.0.0

index.mddocs/

@lit/react

@lit/react provides React integration for Web Components and Reactive Controllers, enabling seamless interoperability between React applications and web components. The library offers utilities for property binding, event handling, and controller composition while maintaining type safety and following React patterns.

Package Information

  • Package Name: @lit/react
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @lit/react

Core Imports

import { createComponent } from "@lit/react";
import type { EventName, ReactWebComponent, WebComponentProps } from "@lit/react";

For the controller hook:

import { useController } from "@lit/react/use-controller.js";
import type { ControllerConstructor } from "@lit/react/use-controller.js";

Basic Usage

Creating React Component Wrappers

import * as React from 'react';
import { createComponent } from '@lit/react';
import { MyElement } from './my-element.js';

export const MyElementComponent = createComponent({
  tagName: 'my-element',
  elementClass: MyElement,
  react: React,
  events: {
    onactivate: 'activate',
    onchange: 'change',
  },
});

// Usage in JSX
<MyElementComponent
  active={isActive}
  onactivate={(e) => setIsActive(e.active)}
/>

Using Reactive Controllers

import * as React from 'react';
import { useController } from '@lit/react/use-controller.js';
import { MouseController } from '@example/mouse-controller';

const useMouse = () => {
  const controller = useController(React, (host) => new MouseController(host));
  return controller.position;
};

const Component = () => {
  const mousePosition = useMouse();
  return <pre>x: {mousePosition.x} y: {mousePosition.y}</pre>;
};

Architecture

@lit/react is built around two main integration patterns:

  • Component Wrapper Pattern: createComponent() creates React components that properly bridge React props and web component properties/events
  • Controller Hook Pattern: useController() adapts Lit's Reactive Controller lifecycle to React's hook system
  • Type Safety: Full TypeScript integration with generic types for custom elements and events
  • Lifecycle Integration: Proper integration with React's render lifecycle using useLayoutEffect
  • Server-Side Rendering: Built-in support for SSR scenarios with @lit/ssr-react

Capabilities

Web Component Integration

Creates React component wrappers for custom elements with proper property binding and event handling, addressing React's default limitations with web components.

/**
 * Creates a React component for a custom element with proper property binding and event handling
 * @param options Configuration object for the component wrapper
 * @returns React ForwardRefExoticComponent that wraps the custom element
 */
function createComponent<I extends HTMLElement, E extends EventNames = {}>(
  options: Options<I, E>
): ReactWebComponent<I, E>;

interface Options<I extends HTMLElement, E extends EventNames = {}> {
  /** The React module, typically imported from the 'react' npm package */
  react: typeof React;
  /** The custom element tag name registered via customElements.define */
  tagName: string;
  /** The custom element class registered via customElements.define */
  elementClass: Constructor<I>;
  /** Object mapping React event prop names to custom element event names */
  events?: E;
  /** React component display name for debugging (defaults to element class name) */
  displayName?: string;
}

type Constructor<T> = { new (): T };
type EventNames = Record<string, EventName | string>;

Reactive Controller Integration

React hook that creates and manages Reactive Controllers using React's lifecycle, enabling controller composition and state management patterns from Lit in React components.

/**
 * Creates and stores a stateful ReactiveController instance with React lifecycle integration
 * @param React The React module providing useState and useLayoutEffect hooks
 * @param createController Function that creates a controller instance given a host
 * @returns The created controller instance
 */
function useController<C extends ReactiveController>(
  React: typeof window.React,
  createController: (host: ReactiveControllerHost) => C
): C;

// ReactiveController and ReactiveControllerHost are imported from @lit/reactive-element
interface ReactiveController {
  hostConnected?(): void;
  hostDisconnected?(): void;
  hostUpdate?(): void;
  hostUpdated?(): void;
}

interface ReactiveControllerHost {
  addController(controller: ReactiveController): void;
  removeController(controller: ReactiveController): void;
  requestUpdate(): void;
  readonly updateComplete: Promise<boolean>;
}

type ControllerConstructor<C extends ReactiveController> = {
  new (...args: Array<any>): C;
};

Type System

Type utilities for enhanced TypeScript integration and type-safe event handling.

/**
 * Props type for web component used directly in React JSX
 */
type WebComponentProps<I extends HTMLElement> = React.DetailedHTMLProps<
  React.HTMLAttributes<I>,
  I
> & ElementProps<I>;

/**
 * Type of the React component wrapping the web component (return type of createComponent)
 */
type ReactWebComponent<I extends HTMLElement, E extends EventNames = {}> = 
  React.ForwardRefExoticComponent<
    ComponentProps<I, E> & React.RefAttributes<I>
  >;

// Helper types used in the API
type ElementProps<I> = Partial<Omit<I, keyof HTMLElement>>;

type ComponentProps<I, E extends EventNames = {}> = Omit<
  React.HTMLAttributes<I>,
  keyof E | keyof ElementProps<I>
> & EventListeners<E> & ElementProps<I>;

type EventListeners<R extends EventNames> = {
  [K in keyof R]?: R[K] extends EventName
    ? (e: R[K]['__eventType']) => void
    : (e: Event) => void;
};

/**
 * Type for casting event names with event types for better typing of event handler props
 * @example
 * events: {
 *   onfoo: 'foo' as EventName<FooEvent>,
 * }
 */
type EventName<T extends Event = Event> = string & {
  __eventType: T;
};

Controller Host Implementation

The library includes a React-driven implementation of ReactiveControllerHost that bridges Lit's controller lifecycle with React hooks through an internal ReactControllerHost class that manages the controller lifecycle using React's useState and useLayoutEffect hooks.

Event Handling

Enhanced event handling with type safety for custom element events.

Basic Event Mapping:

const Component = createComponent({
  tagName: 'my-element',
  elementClass: MyElement,
  react: React,
  events: {
    onchange: 'change',
    oncustom: 'custom-event',
  },
});

Type-Safe Event Handling:

import type { EventName } from '@lit/react';

const Component = createComponent({
  tagName: 'my-element',
  elementClass: MyElement,
  react: React,
  events: {
    onClick: 'pointerdown' as EventName<PointerEvent>,
    onChange: 'input',
  },
});

// Usage with properly typed event handlers
<Component
  onClick={(e: PointerEvent) => console.log('Pointer event:', e)}
  onChange={(e: Event) => console.log('Input event:', e)}
/>

Server-Side Rendering

The library includes built-in support for server-side rendering when used with @lit/ssr-react:

// SSR support is automatically enabled when litSsrReactEnabled is true
// or when React.createElement.name === 'litPatchedCreateElement'

Error Handling

The library provides development-time warnings for potential integration issues:

  • Warns when custom elements define properties that conflict with React reserved properties
  • Handles property/attribute synchronization edge cases
  • Provides proper cleanup for event listeners and controller lifecycle