Files
gh-djankies-claude-configs-…/skills/supporting-custom-elements/SKILL.md
2025-11-29 18:22:28 +08:00

4.6 KiB

name, description, allowed-tools, version
name description allowed-tools version
supporting-custom-elements Teaches Web Components (Custom Elements) support in React 19, including property vs attribute handling and custom events. Use when integrating Web Components or working with custom HTML elements. Read, Write, Edit 1.0.0

Web Components Support in React 19

This skill teaches you how to use Web Components (Custom Elements) in React 19, which now has full support. This skill activates when:
  • Working with Web Components or Custom Elements
  • Integrating third-party web components
  • Passing props to custom elements
  • Handling custom events from web components
  • Migration from React 18 web component workarounds
React 19 adds full support for Custom Elements and passes all Custom Elements Everywhere tests.

New in React 19:

  1. Automatic Property Detection - React determines property vs attribute
  2. Custom Event Support - Standard on + EventName convention
  3. Boolean Attributes - Properly handled (added/removed as needed)
  4. No Ref Workarounds - Pass props directly to custom elements

Before React 19:

<web-counter
  ref={(el) => {
    if (el) {
      el.increment = increment;
      el.isDark = isDark;
    }
  }}
/>

React 19:

<web-counter increment={increment} isDark={isDark} onIncrementEvent={() => setCount(count + 1)} />
## Using Web Components

Step 1: Define Custom Element (or use third-party)

class WebCounter extends HTMLElement {
  connectedCallback() {
    this.render();
  }

  set increment(fn) {
    this._increment = fn;
  }

  set isDark(value) {
    this._isDark = value;
    this.render();
  }

  handleClick() {
    this._increment?.();
    this.dispatchEvent(new CustomEvent('incremented'));
  }

  render() {
    this.innerHTML = `
      <button style="color: ${this._isDark ? 'white' : 'black'}">
        Increment
      </button>
    `;
    this.querySelector('button').onclick = () => this.handleClick();
  }
}

customElements.define('web-counter', WebCounter);

Step 2: Use in React 19

function App() {
  const [count, setCount] = useState(0);
  const [isDark, setIsDark] = useState(false);

  const increment = () => setCount(count + 1);

  return (
    <div>
      <p>Count: {count}</p>

      <web-counter
        increment={increment}
        isDark={isDark}
        onIncremented={() => console.log('Incremented!')}
      />

      <button onClick={() => setIsDark(!isDark)}>Toggle Theme</button>
    </div>
  );
}

Step 3: Handle Custom Events

Custom events follow on + EventName convention:

<my-button label="Click Me" onButtonClick={handleClick} />

If custom element dispatches buttonClick event, React automatically wires it up.

## Example: Third-Party Web Component
import '@material/mwc-button';

function MaterialButton() {
  return <mwc-button raised label="Click me" icon="code" onClick={() => alert('Clicked!')} />;
}

Example: Custom Form Element

class RatingInput extends HTMLElement {
  connectedCallback() {
    this.rating = 0;
    this.render();
  }

  setRating(value) {
    this.rating = value;
    this.dispatchEvent(
      new CustomEvent('ratingChange', {
        detail: { rating: value },
      })
    );
    this.render();
  }

  render() {
    this.innerHTML = `
      ${[1, 2, 3, 4, 5]
        .map(
          (i) => `
        <button data-rating="${i}">⭐</button>
      `
        )
        .join('')}
    `;

    this.querySelectorAll('button').forEach((btn) => {
      btn.onclick = () => this.setRating(+btn.dataset.rating);
    });
  }
}

customElements.define('rating-input', RatingInput);
function ReviewForm() {
  const [rating, setRating] = useState(0);

  return (
    <form>
      <rating-input onRatingChange={(e) => setRating(e.detail.rating)} />
      <p>Rating: {rating}</p>
    </form>
  );
}

For comprehensive Custom Elements documentation, see: research/react-19-comprehensive.md lines 1034-1089.

## MUST - Use standard `on + EventName` for custom events - Let React determine property vs attribute automatically - Define custom elements before using in React

SHOULD

  • Prefer Web Components for framework-agnostic widgets
  • Use TypeScript declarations for custom elements
  • Test SSR vs CSR rendering differences

NEVER

  • Use ref workarounds (React 19 handles props directly)
  • Forget to define custom elements (will render as unknown tag)
  • Pass non-primitive values in SSR context (will be omitted)