supporting-custom-elements

📁 djankies/claude-configs 📅 9 days ago
1
总安装量
1
周安装量
#48636
全站排名
安装命令
npx skills add https://github.com/djankies/claude-configs --skill supporting-custom-elements

Agent 安装分布

replit 1
junie 1
windsurf 1
trae 1
qoder 1
opencode 1

Skill 文档

Web Components Support in React 19

  • 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

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)} />

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.

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.

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)