or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-lit-labs--react

A React component wrapper for web components that has graduated from labs and now serves as a proxy to @lit/react

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

To install, run

npx @tessl/cli install tessl/npm-lit-labs--react@2.1.0

index.mddocs/

@lit-labs/react

React integration for Web Components and Reactive Controllers. This package has graduated from labs and now serves as a proxy that re-exports functionality from @lit/react while maintaining compatibility during the ecosystem migration.

Package Information

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

Core Imports

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

For CommonJS:

const { createComponent } = require("@lit-labs/react");
const { useController } = require("@lit-labs/react/use-controller.js");

Basic Usage

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

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

// Use the component in JSX
function App() {
  const [isActive, setIsActive] = React.useState(false);
  
  return (
    <MyElementComponent
      active={isActive}
      onactivate={(e) => setIsActive(e.active)}
      onchange={(e) => console.log('Changed:', e.detail)}
    />
  );
}

Architecture

@lit-labs/react provides two main utilities:

  • createComponent: Creates React component wrappers for custom elements that correctly handle property passing and event handling
  • useController: React hook that allows using Reactive Controllers within React components with proper lifecycle integration
  • Type System: Full TypeScript support with generic types for custom elements and events
  • Proxy Pattern: All functionality is re-exported from @lit/react to maintain compatibility during migration

Capabilities

Component Creation

Creates React component wrappers for custom elements with proper property and event handling.

/**
 * Creates a React component for a custom element
 * @param options Configuration object for the wrapper component
 * @returns React component 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 prop names to custom element event names */
  events?: E;
  /** React component display name, used in debugging messages */
  displayName?: string;
}

type Constructor<T> = { new (): T };

type EventNames = Record<string, EventName | string>;

Usage Examples:

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

// Basic component creation
const MyElementComponent = createComponent({
  tagName: 'my-element',
  elementClass: MyElement,
  react: React,
});

// Component with event mapping
const InteractiveComponent = createComponent({
  tagName: 'interactive-element',
  elementClass: InteractiveElement,
  react: React,
  events: {
    onactivate: 'activate',
    onchange: 'change',
    onclick: 'click',
  },
  displayName: 'InteractiveElement',
});

Controller Integration

React hook for using Reactive Controllers within React components.

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

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

Usage Examples:

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

// Create a React hook using a controller
const useMouse = () => {
  const controller = useController(React, (host) => new MouseController(host));
  return controller.position;
};

// Use the controller hook in a React component
const Component = () => {
  const mousePosition = useMouse();
  return (
    <pre>
      x: {mousePosition.x}
      y: {mousePosition.y}
    </pre>
  );
};

// Direct controller usage
const MyComponent = () => {
  const myController = useController(React, (host) => new MyCustomController(host));
  
  return (
    <div>
      <p>Controller state: {myController.value}</p>
      <button onClick={() => myController.increment()}>
        Increment
      </button>
    </div>
  );
};

Types

/**
 * Type used to cast event names with specific event types for better typing
 */
type EventName<T extends Event = Event> = string & {
  __eventType: T;
};

/**
 * Type of the React component wrapping the web component
 */
type ReactWebComponent<
  I extends HTMLElement,
  E extends EventNames = {}
> = React.ForwardRefExoticComponent<
  React.HTMLAttributes<I> & Partial<Omit<I, keyof HTMLElement>> & React.RefAttributes<I>
>;

/**
 * Creates a type for props of a web component used directly in React JSX
 */
type WebComponentProps<I extends HTMLElement> = React.DetailedHTMLProps<
  React.HTMLAttributes<I>,
  I
>;

/**
 * Type for constructor functions that create ReactiveController instances
 */
type ControllerConstructor<C extends ReactiveController> = {
  new (...args: Array<any>): C;
};

/**
 * External types from @lit/reactive-element (not part of @lit-labs/react API)
 * These interfaces are imported when using useController
 */
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>;
}

Advanced Usage

Event Type Casting

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

// Define typed events for better type safety
const MyElementComponent = createComponent({
  tagName: 'my-element',
  elementClass: MyElement,
  react: React,
  events: {
    onClick: 'pointerdown' as EventName<PointerEvent>,
    onChange: 'input' as EventName<InputEvent>,
  },
});

// Now event callbacks are properly typed
<MyElementComponent
  onClick={(e: PointerEvent) => console.log('Pointer event:', e)}
  onChange={(e: InputEvent) => console.log('Input event:', e)}
/>

JSX Declaration

declare module 'react' {
  namespace JSX {
    interface IntrinsicElements {
      'my-element': WebComponentProps<MyElement>;
    }
  }
}

// Now you can use the element directly in JSX
<my-element customProp={value} onCustomEvent={handler} />

Error Handling

  • Missing Element Class: createComponent will warn if reserved React properties are found on the element prototype
  • Event Handler Errors: Event listeners are automatically managed; errors in handlers should be caught by the consuming application
  • Controller Lifecycle: useController handles React Strict Mode correctly and manages controller lifecycle automatically

Server-Side Rendering

Components created with createComponent support server-side rendering when used with @lit/ssr-react. The wrapper handles:

  • Adding defer-hydration attribute to prevent hydration warnings
  • Passing element properties through _$litProps$ for server rendering
  • Automatic hydration suppression warning management
// SSR usage (works automatically with @lit/ssr-react)
const ServerRenderedComponent = createComponent({
  tagName: 'my-element',
  elementClass: MyElement,
  react: React,
});

// Component will render properly on server and hydrate correctly on client
<ServerRenderedComponent customProp={value} />

Migration Notes

This package is deprecated and serves as a compatibility layer. For new projects, use @lit/react directly:

// Old (deprecated but still works)
import { createComponent } from '@lit-labs/react';

// New (recommended)
import { createComponent } from '@lit/react';