or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

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

0

# @lit-labs/react

1

2

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.

3

4

## Package Information

5

6

- **Package Name**: @lit-labs/react

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install @lit-labs/react`

10

11

## Core Imports

12

13

```typescript

14

import { createComponent } from "@lit-labs/react";

15

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

16

```

17

18

For CommonJS:

19

20

```javascript

21

const { createComponent } = require("@lit-labs/react");

22

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

23

```

24

25

## Basic Usage

26

27

```typescript

28

import * as React from 'react';

29

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

30

import { MyElement } from './my-element.js';

31

32

// Create React component wrapper for custom element

33

export const MyElementComponent = createComponent({

34

tagName: 'my-element',

35

elementClass: MyElement,

36

react: React,

37

events: {

38

onactivate: 'activate',

39

onchange: 'change',

40

},

41

});

42

43

// Use the component in JSX

44

function App() {

45

const [isActive, setIsActive] = React.useState(false);

46

47

return (

48

<MyElementComponent

49

active={isActive}

50

onactivate={(e) => setIsActive(e.active)}

51

onchange={(e) => console.log('Changed:', e.detail)}

52

/>

53

);

54

}

55

```

56

57

## Architecture

58

59

@lit-labs/react provides two main utilities:

60

61

- **createComponent**: Creates React component wrappers for custom elements that correctly handle property passing and event handling

62

- **useController**: React hook that allows using Reactive Controllers within React components with proper lifecycle integration

63

- **Type System**: Full TypeScript support with generic types for custom elements and events

64

- **Proxy Pattern**: All functionality is re-exported from `@lit/react` to maintain compatibility during migration

65

66

## Capabilities

67

68

### Component Creation

69

70

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

71

72

```typescript { .api }

73

/**

74

* Creates a React component for a custom element

75

* @param options Configuration object for the wrapper component

76

* @returns React component that wraps the custom element

77

*/

78

function createComponent<I extends HTMLElement, E extends EventNames = {}>(

79

options: Options<I, E>

80

): ReactWebComponent<I, E>;

81

82

interface Options<I extends HTMLElement, E extends EventNames = {}> {

83

/** The React module, typically imported from the 'react' npm package */

84

react: typeof React;

85

/** The custom element tag name registered via customElements.define */

86

tagName: string;

87

/** The custom element class registered via customElements.define */

88

elementClass: Constructor<I>;

89

/** Object mapping React prop names to custom element event names */

90

events?: E;

91

/** React component display name, used in debugging messages */

92

displayName?: string;

93

}

94

95

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

96

97

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

98

```

99

100

**Usage Examples:**

101

102

```typescript

103

import * as React from 'react';

104

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

105

import { MyElement } from './my-element.js';

106

107

// Basic component creation

108

const MyElementComponent = createComponent({

109

tagName: 'my-element',

110

elementClass: MyElement,

111

react: React,

112

});

113

114

// Component with event mapping

115

const InteractiveComponent = createComponent({

116

tagName: 'interactive-element',

117

elementClass: InteractiveElement,

118

react: React,

119

events: {

120

onactivate: 'activate',

121

onchange: 'change',

122

onclick: 'click',

123

},

124

displayName: 'InteractiveElement',

125

});

126

```

127

128

### Controller Integration

129

130

React hook for using Reactive Controllers within React components.

131

132

```typescript { .api }

133

/**

134

* Creates and stores a stateful ReactiveController instance with React lifecycle

135

* @param React The React module that provides the base hooks (useState, useLayoutEffect)

136

* @param createController Function that creates a controller instance given a host

137

* @returns The controller instance

138

*/

139

function useController<C extends ReactiveController>(

140

React: typeof window.React,

141

createController: (host: ReactiveControllerHost) => C

142

): C;

143

144

type ControllerConstructor<C extends ReactiveController> = {

145

new (...args: Array<any>): C;

146

};

147

```

148

149

**Usage Examples:**

150

151

```typescript

152

import * as React from 'react';

153

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

154

import { MouseController } from '@example/mouse-controller';

155

156

// Create a React hook using a controller

157

const useMouse = () => {

158

const controller = useController(React, (host) => new MouseController(host));

159

return controller.position;

160

};

161

162

// Use the controller hook in a React component

163

const Component = () => {

164

const mousePosition = useMouse();

165

return (

166

<pre>

167

x: {mousePosition.x}

168

y: {mousePosition.y}

169

</pre>

170

);

171

};

172

173

// Direct controller usage

174

const MyComponent = () => {

175

const myController = useController(React, (host) => new MyCustomController(host));

176

177

return (

178

<div>

179

<p>Controller state: {myController.value}</p>

180

<button onClick={() => myController.increment()}>

181

Increment

182

</button>

183

</div>

184

);

185

};

186

```

187

188

## Types

189

190

```typescript { .api }

191

/**

192

* Type used to cast event names with specific event types for better typing

193

*/

194

type EventName<T extends Event = Event> = string & {

195

__eventType: T;

196

};

197

198

/**

199

* Type of the React component wrapping the web component

200

*/

201

type ReactWebComponent<

202

I extends HTMLElement,

203

E extends EventNames = {}

204

> = React.ForwardRefExoticComponent<

205

React.HTMLAttributes<I> & Partial<Omit<I, keyof HTMLElement>> & React.RefAttributes<I>

206

>;

207

208

/**

209

* Creates a type for props of a web component used directly in React JSX

210

*/

211

type WebComponentProps<I extends HTMLElement> = React.DetailedHTMLProps<

212

React.HTMLAttributes<I>,

213

I

214

>;

215

216

/**

217

* Type for constructor functions that create ReactiveController instances

218

*/

219

type ControllerConstructor<C extends ReactiveController> = {

220

new (...args: Array<any>): C;

221

};

222

223

/**

224

* External types from @lit/reactive-element (not part of @lit-labs/react API)

225

* These interfaces are imported when using useController

226

*/

227

interface ReactiveController {

228

hostConnected?(): void;

229

hostDisconnected?(): void;

230

hostUpdate?(): void;

231

hostUpdated?(): void;

232

}

233

234

interface ReactiveControllerHost {

235

addController(controller: ReactiveController): void;

236

removeController(controller: ReactiveController): void;

237

requestUpdate(): void;

238

readonly updateComplete: Promise<boolean>;

239

}

240

```

241

242

## Advanced Usage

243

244

### Event Type Casting

245

246

```typescript

247

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

248

249

// Define typed events for better type safety

250

const MyElementComponent = createComponent({

251

tagName: 'my-element',

252

elementClass: MyElement,

253

react: React,

254

events: {

255

onClick: 'pointerdown' as EventName<PointerEvent>,

256

onChange: 'input' as EventName<InputEvent>,

257

},

258

});

259

260

// Now event callbacks are properly typed

261

<MyElementComponent

262

onClick={(e: PointerEvent) => console.log('Pointer event:', e)}

263

onChange={(e: InputEvent) => console.log('Input event:', e)}

264

/>

265

```

266

267

### JSX Declaration

268

269

```typescript

270

declare module 'react' {

271

namespace JSX {

272

interface IntrinsicElements {

273

'my-element': WebComponentProps<MyElement>;

274

}

275

}

276

}

277

278

// Now you can use the element directly in JSX

279

<my-element customProp={value} onCustomEvent={handler} />

280

```

281

282

## Error Handling

283

284

- **Missing Element Class**: `createComponent` will warn if reserved React properties are found on the element prototype

285

- **Event Handler Errors**: Event listeners are automatically managed; errors in handlers should be caught by the consuming application

286

- **Controller Lifecycle**: `useController` handles React Strict Mode correctly and manages controller lifecycle automatically

287

288

## Server-Side Rendering

289

290

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

291

292

- Adding `defer-hydration` attribute to prevent hydration warnings

293

- Passing element properties through `_$litProps$` for server rendering

294

- Automatic hydration suppression warning management

295

296

```typescript

297

// SSR usage (works automatically with @lit/ssr-react)

298

const ServerRenderedComponent = createComponent({

299

tagName: 'my-element',

300

elementClass: MyElement,

301

react: React,

302

});

303

304

// Component will render properly on server and hydrate correctly on client

305

<ServerRenderedComponent customProp={value} />

306

```

307

308

## Migration Notes

309

310

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

311

312

```typescript

313

// Old (deprecated but still works)

314

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

315

316

// New (recommended)

317

import { createComponent } from '@lit/react';

318

```