Skip to content
Skills Library
Programming · Learning & explanation

react

/react

Show how to use custom elements in React, including workarounds for React 18 vs 19 differences. Use when the user asks to "use in React", "React wrapper", "custom elements in React", "JSX custom element", or mentions "React 18", "React 19", or "react integration".

Repository
cem ↗
Licence
GPL-3.0
Last repository change
26.10.2026

Assessment and security

100/ 100Class: good
Format25 / 25
Frontmatter with name and description, valid name, description up to 1,024 characters, name matching the folder.
Discoverability25 / 25
Description explains when to use the skill, has a reasonable length and uses third person.
Content35 / 35
At least 150 words and at most 500 lines, headings, step lists, examples or code.
Hygiene15 / 15
No placeholders such as TODO, no Windows paths, with a licence.
Riskno signals detected in the scan
Files in this package
1
Scripts
0
HTML comments
0
URLs in SKILL.md
0
Deprecation

No signals detected. Repository changed on 26.10.2026, without references to retired models or APIs.

Licence

GPL-3.0, otwarta.

What it does and when to use it

Show how to use custom elements in React, including workarounds for React 18 vs 19 differences. Use when the user asks to "use in React", "React wrapper", "custom elements in React", "JSX custom element", or mentions "React 18", "React 19", or "react integration".

Triggers from the description

use in ReactReact wrappercustom elements in ReactJSX custom elementReact 18React 19react integration
Original author description

Show how to use custom elements in React, including workarounds for React 18 vs 19 differences. Use when the user asks to "use in React", "React wrapper", "custom elements in React", "JSX custom element", or mentions "React 18", "React 19", or "react integration".

How it works

  1. Workflow
  2. React Version Reference
  3. Guidelines
Original SKILL.md headings · 214 lines, 802 words
SKILL.md preview
---
name: react
description: Show how to use custom elements in React, including workarounds for React 18 vs 19 differences. Use when the user asks to "use in React", "React wrapper", "custom elements in React", "JSX custom element", or mentions "React 18", "React 19", or "react integration".
tools: Read, Glob, Grep
---

# Custom Elements in React

Generate framework-specific guidance for using custom elements in React, adapting to the project's React version.

## Workflow

### Phase 1: Detect React Version

Search the project for React version:

```bash
# Check package.json for react version
grep -A1 '"react"' package.json
```

Determine if the project uses:
- **React 19+**: Native custom element support
- **React 18 or earlier**: Requires workarounds for properties and events

Also check for:
- TypeScript (need JSX type declarations)
- Existing wrapper patterns in the codebase
- Whether `@lit/react` or similar wrapper libraries are already in use

### Phase 2: Gather Element Data

Read the target element(s):

```text
cem://element/{tagName}
cem://element/{tagName}/attributes
cem://element/{tagName}/events
```

Understand the element's API to know which features need framework-specific handling:
- **Attributes** (string-only): Work in all React versions
- **Properties** (complex types): Need workarounds in React 18
- **Events** (custom events): Need workarounds in React 18
- **Slots**: Map to `children` and named slot patterns in JSX
- **Boolean attributes**: Differ between React and HTML semantics

### Phase 3: Generate Integration Code

#### React 19+

React 19 supports custom elements natively. Properties are set correctly and custom events are handled.

```tsx
// Direct usage — no wrappers needed
function MyComponent() {
  return (
    <my-element
      variant="primary"
      complexData={someObject}
      onMyEvent={(e) => handleEvent(e)}
    >
      <span slot="icon">★</span>
      Button text
    </my-element>
  );
}
```

Key React 19 behaviors:
- Props matching an element property are set as properties, not attributes
- `on` + PascalCase event name maps to custom events (e.g., `onChange` -> `change`)
- `className` is set as the `class` attribute
- Boolean attributes work correctly

#### React 18 and Earlier

React 18 treats custom elements like unknown HTML elements — all props are set as attributes (stringified), and custom events are not supported via JSX.

**Option A: Use `@lit/react` wrappers (recommended)**

```tsx
import { createComponent } from '@lit/react';
import { MyElement } from 'my-element-library';

export const MyElementReact = createComponent({
  tagName: 'my-element',
  elementClass: MyElement,
  react: React,
  events: {
    onMyEvent: 'my-event',
    onChange: 'change',
  },
});

// Usage
function MyComponent() {
  return (
    <MyElementReact
      variant="primary"
      complexData={someObject}
      onMyEvent={(e) => handleEvent(e)}
    >
      Button text
    </MyElementReact>
  );
}
```

**Option B: Use refs for properties and events**

```tsx
function MyComponent() {
  const ref = useRef<HTMLElement>(null);

  useEffect(() => {
    const el = ref.current;
    if (!el) return;

    // Set complex properties via ref
    (el as any).complexData = someObject;

    // Add event listeners
    const handler = (e: Event) => handleEvent(e);
    el.addEventListener('my-event', handler);
    return () => el.removeEventListener('my-event', handler);
  }, [someObject]);

  return (
    <my-element ref={ref} variant="primary">
      Button text
    </my-element>
  );
}
```

**Option C: Use the CEM `export react` wrappers**

If the project uses CEM's export command, check for pre-generated React wrappers:

```bash
cem export react
```

This generates typed React wrapper components from the manifest.

#### TypeScript Declarations

For both React versions, add JSX type declarations so TypeScript knows about custom element attributes:

```tsx
// custom-elements.d.ts
import type { MyElement } from 'my-element-library';

declare global {
  namespace JSX {
    interface IntrinsicElements {
      'my-element': React.DetailedHTMLProps<
        React.HTMLAttributes<MyElement> & {
          variant?: 'primary' | 'secondary';
          disabled?: boolean;
          // For React 18: only string attributes here
          // For React 19: include property types too
        },
        MyElement
      >;
    }
  }
}
```

For React 19, the declaration can include complex property types. For React 18, only include attributes (strings/booleans) since complex types won't pass through correctly without a wrapper.

#### Slot Mapping

Map named slots to JSX:

```tsx
// HTML slots -> JSX
<my-element>
  {/* Default slot */}
  <span>Default content</span>

  {/* Named slots */}
  <span slot="header">Header content</span>
  <span slot="footer">Footer content</span>
</my-element>
```

### Phase 4: Output

Present the integration code with:

1. **Version-appropriate code**: Only show React 19 patterns if the project uses React 19+
2. **TypeScript declarations**: If the project uses TypeScript
3. **Event handling**: For each event in the manifest
4. **Property passing**: For each non-string property
5. **Import statements**: Show how to import the element registration

## React Version Reference

| Feature | React 18 | React 19+ |
|---------|----------|-----------|
| String attributes | Passed as attributes | Passed as attributes |
| Boolean attributes | `""` or `undefined` | Correct HTML behavior |
| Complex properties | Stringified (broken) | Set as properties |
| Custom events | Not supported in JSX | `onEventName` works |
| `className` | Set as attribute | Set as `class` |
| `ref` | Works | Works |
| SSR | Attributes only | Attributes only |

## Guidelines

- **Check the React version first**: The guidance differs significantly between 18 and 19
- **Prefer `@lit/react` wrappers for React 18**: They handle properties and events correctly with minimal boilerplate
- **Generate TypeScript declarations from the manifest**: The element's attributes and their types are all available
- **Don't suggest `dangerouslySetInnerHTML`**: Custom elements use slots, not innerHTML
- **Handle SSR**: Note that server-rendered custom elements only have access to attributes, not properties

Versions

RepositoryScoreLicence
This page · bennypowers/cem100GPL-3.0
ericrisco/rsc-harness100MIT
mintuz/claude-plugins100MIT
frankxai/claude-skills-library100MIT
kriscard/Skills100MIT
xobotyi/cc-foundry100MIT
openops-cloud/openops100Apache-2.0
nimadorostkar/Claude-Skills-collection100MIT
atinder-harika/reel-reactor100MIT

Database snapshot: 13.11.2026 · package version 03884090bc97 (SHA-256 digest of the entire package)

Downloads in the last 30 days: 0 · ranking

Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.

Similar skills

  • 100vue
    Show how to use custom elements in Vue, including required configuration for the Vue compiler. Use when the user asks to "use in Vue", "Vue custom elements", "custom elements in Vue", "isCustomElement", or mentions "Vue 3", "Vue 2", "Nuxt", or "vue integration".
  • 100angular
    Show how to use custom elements in Angular, including required CUSTOM_ELEMENTS_SCHEMA configuration. Use when the user asks to "use in Angular", "Angular custom elements", "custom elements in Angular", "CUSTOM_ELEMENTS_SCHEMA", or mentions "Angular module", "standalone…
  • 90Custom Component Builder
    Build custom React/JSX interface components with the @noclick/sdk. Use when the user asks to create a custom component, build an interface, create a dashboard, add a custom UI, use the SDK, or mentions component, interface-html-react, jsx_source, fullscreen component, or @noclick/sdk.
  • 100react-best-practices
    Use when reading or writing React components (.tsx, .jsx files with React imports).
  • 95fp-ts-react
    Practical patterns for using fp-ts with React - hooks, state, forms, data fetching. Use when building React apps with functional programming patterns. Works with React 18/19, Next.js 14/15.
  • 100developing-with-react
    React 18+ development with hooks, state management, component patterns, and Next.js integration. Use when building React applications or working with JSX/TSX components.

Feedback and reports

Your message goes to Bartosz Sokoliński. An email address is needed only for a reply. See the privacy policy.