{"id":10616,"library":"ce-la-react","title":"ce-la-react","description":"ce-la-react is a utility library designed to simplify the integration of vanilla custom elements with React components, providing a wrapper that addresses common issues with prop passing and event handling. The current stable version is 0.3.2. It maintains a fairly active release cadence with frequent patch releases, indicating ongoing development. A key differentiator from similar libraries like `@lit/react` is its stronger emphasis on server-side rendering (SSR) by favoring attributes over properties for primitive values. It also offers configurable conversion functions for properties to attributes and supports custom element templates via a static `getTemplateHTML` method, offering a robust solution for developers building component libraries with Web Components that need to be consumed by React applications.","status":"active","version":"0.3.2","language":"javascript","source_language":"en","source_url":"https://github.com/muxinc/ce-la-react","tags":["javascript","typescript"],"install":[{"cmd":"npm install ce-la-react","lang":"bash","label":"npm"},{"cmd":"yarn add ce-la-react","lang":"bash","label":"yarn"},{"cmd":"pnpm add ce-la-react","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required as a peer dependency for creating and using React components and their APIs.","package":"react","optional":false}],"imports":[{"note":"The library primarily uses ES module syntax. While CJS might work via transpilation, direct ESM imports are recommended for modern React projects.","wrong":"const { createComponent } = require('ce-la-react');","symbol":"createComponent","correct":"import { createComponent } from 'ce-la-react';"},{"note":"Used for type casting custom event names in TypeScript to provide strong typing for event callbacks. Always import as a type.","symbol":"EventName","correct":"import type { EventName } from 'ce-la-react';"},{"note":"Ensure you import React correctly based on your project's `tsconfig.json` (e.g., 'preserve' or 'react-jsx') and React version. `import * as React` is generally safe.","wrong":"import React from 'react';","symbol":"React","correct":"import * as React from 'react';"}],"quickstart":{"code":"import * as React from 'react';\nimport { createComponent } from 'ce-la-react';\nimport type { EventName } from 'ce-la-react';\n\n// Define a simple custom element for demonstration purposes\nclass MyToggleElement extends HTMLElement {\n  static observedAttributes = ['active'];\n  private _active: boolean = false;\n\n  constructor() {\n    super();\n    this.attachShadow({ mode: 'open' });\n    this.shadowRoot!.innerHTML = `<style>\n      :host { display: inline-block; padding: 8px; border: 1px solid #ccc; border-radius: 4px; }\n      button { padding: 8px 12px; cursor: pointer; background: #007bff; color: white; border: none; border-radius: 3px; }\n      button.active { background: #28a745; }\n    </style>\n    <button>${this._active ? 'Active' : 'Inactive'}</button>`;\n\n    this.shadowRoot!.querySelector('button')!.onclick = () => {\n      this.active = !this.active;\n    };\n  }\n\n  set active(value: boolean) {\n    if (this._active === value) return;\n    this._active = value;\n    if (value) {\n      this.setAttribute('active', '');\n    } else {\n      this.removeAttribute('active');\n    }\n    this.updateButtonText();\n    this.dispatchEvent(new CustomEvent('toggle', { detail: { active: value }, bubbles: true, composed: true }));\n  }\n\n  get active(): boolean {\n    return this._active;\n  }\n\n  attributeChangedCallback(name: string, oldValue: string, newValue: string) {\n    if (name === 'active') {\n      this.active = newValue !== null;\n    }\n  }\n\n  private updateButtonText() {\n    const button = this.shadowRoot!.querySelector('button');\n    if (button) {\n      button.textContent = this._active ? 'Active' : 'Inactive';\n      button.classList.toggle('active', this._active);\n    }\n  }\n}\n\ncustomElements.define('my-toggle-element', MyToggleElement);\n\ninterface ToggleEventDetail { active: boolean; }\n\n// Create the React component wrapper\nexport const MyToggleComponent = createComponent({\n  tagName: 'my-toggle-element',\n  elementClass: MyToggleElement,\n  react: React,\n  events: {\n    onToggle: 'toggle' as EventName<CustomEvent<ToggleEventDetail>>\n  },\n});\n\n// Example React usage\nexport function App() {\n  const [isActive, setIsActive] = React.useState(false);\n\n  return (\n    <div>\n      <h1>ce-la-react Custom Element Demo</h1>\n      <p>React State: {isActive ? 'ON' : 'OFF'}</p>\n      <MyToggleComponent\n        active={isActive}\n        onToggle={(e: CustomEvent<ToggleEventDetail>) => {\n          console.log('Custom event received:', e.detail.active);\n          setIsActive(e.detail.active);\n        }}\n      />\n      <p>Click the custom element button to toggle its state and see React update.</p>\n    </div>\n  );\n}\n\n// To run this in a real app, you would typically render `App`:\n// import { createRoot } from 'react-dom/client';\n// const container = document.getElementById('root');\n// if (container) {\n//   const root = createRoot(container);\n//   root.render(<App />);\n// }\n","lang":"typescript","description":"This code demonstrates how to create a React component wrapper for a custom element using `createComponent`. It includes a minimal, self-contained custom element definition and shows how to pass props from React to the custom element and listen for custom events with type-safety using `EventName`."},"warnings":[{"fix":"Always use `EventName<CustomEvent<DetailType>>` for custom event type definitions in the `events` map passed to `createComponent`.","message":"When defining event callbacks in TypeScript, it is crucial to explicitly cast the event name using `EventName<YourCustomEventType>` (e.g., `onToggle: 'toggle' as EventName<CustomEvent<ToggleEventDetail>>`). Failing to do so will cause the event parameter in the React callback to default to a generic `Event` type, leading to potential type errors or missing properties.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Upgrade to `ce-la-react` version 0.2.1 or newer to ensure proper handling of complex reflected properties and attributes with React 19+.","message":"While `ce-la-react` aims for improved React 19+ compatibility, earlier versions (specifically `<0.2.1`) had a bug related to 'complex reflected prop/attr' handling with React 19+. Users experiencing issues with complex properties or attributes might be on an outdated version.","severity":"breaking","affected_versions":"<0.2.1"},{"fix":"Review the documentation on 'Converting `props` to attributes' and understand how primitive values are serialized to attributes. If specific property-based control is needed, ensure the custom element is designed to reflect changes from attributes back to properties.","message":"`ce-la-react` prioritizes attributes over properties for primitive values to enhance Server-Side Rendering (SSR) compatibility. Developers accustomed to directly setting properties on custom elements in React might need to adjust their mental model, particularly for primitive data types.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure that your SSR setup either mocks `HTMLElement` (and other DOM APIs) or that the custom element definition is guarded to only run in a browser environment, or use a tool that provides a browser-like environment for SSR.","cause":"This error typically occurs during server-side rendering (SSR) if the Node.js environment does not have a global `HTMLElement` available, which is a browser-specific API.","error":"ReferenceError: HTMLElement is not defined"},{"fix":"Upgrade to `ce-la-react` version 0.3.1 or newer. If the issue persists, review your `core-js` polyfill configuration to ensure it's compatible with modern browser APIs and custom element specifications.","cause":"This specific error ('elementClass.prototype undefined error with corejs polyfill') was a known bug related to interactions with `core-js` polyfills, especially in older versions.","error":"TypeError: Cannot set properties of undefined (setting 'active') or elementClass.prototype undefined"},{"fix":"In your `createComponent` configuration, explicitly type cast your custom event names. For example, `events: { onMyEvent: 'my-event' as EventName<CustomEvent<MyDetail>> }`.","cause":"This TypeScript error occurs when a custom event callback expects a specific `CustomEvent` type (e.g., `CustomEvent<MyDetail>`) but the `events` map in `createComponent` was not correctly type-casted with `EventName<CustomEvent<MyDetail>>`, causing the callback parameter to default to the generic `Event` type.","error":"Type 'CustomEvent<MyDetail>' is not assignable to type 'Event'"}],"ecosystem":"npm"}