<react-root></react-root>
output {
  display: block;

  span {
    border: 2px solid rebeccapurple;
    padding: 0.15rem 1rem;
    border-radius: 6px;
  }
}

body {
  height: 100vh;
  margin: 0;
  display: grid;
  place-items: center;
  text-align: center;
  font: 800 100%/1.8 system-ui, sans-serif;
}

.react-component {
  border: 2px solid #2196f3;
  padding: 2rem;
  h2 {
    margin: 0 0 1rem 0;
    color: #2196f3;
  }
}

my-button {
  display: block;
  border: 2px solid #f57f17;
  padding: 2rem;
  margin: 0 0 2rem 0;

  &[neato-custom-attribute] {
    box-shadow: 0 0 20px oklch(70% 0 0);
  }
}
.web-component-header.web-component-header {
  margin: 0 0 1rem 0;
  color: #f57f17;
}
import React, { useState } from "https://esm.sh/react@19";
import { LitElement, html, css } from "https://esm.sh/lit";
import { createRoot } from "https://esm.sh/react-dom@19/client";

/* Web Component */
customElements.define(
  "my-button",
  class extends LitElement {
    static properties = {
      count: { type: Number },
      funcInReactComponent: {
        type: Function,
        attribute: false
      }
    };

    constructor() {
      super();
      this.count = 0;
    }

    connectedCallback() {
      super.connectedCallback();
    }

    handleClick() {
      this.count++;
      // this.funcInReactComponent();
    }

    // Force Light DOM (not necessary - just easier styling)
    createRenderRoot() {
      return this;
    }

    render() {
      return html`
        <h2 class="web-component-header">Web Component</h2>
        <button @click="${this.handleClick}">Web Component Button</button>
        <output>
          Count tracked in Web Component:
          <span>${this.count}</span>
        </output>
      `;
    }
  }
);

/* React Component */
const MyReactComponent = () => {
  const [count, setCount] = useState(0);

  function funcInReactComponent() {
    alert("function in React Component called!");
  }

  return (
    <div className="react-component">
      <h2>React Component</h2>
      <my-button
        neato-custom-attribute
        // Can't pass functions in, because (Babel?) hates this syntax.
        // .customFunc={funcInReactComponent}

        // Click handler on entire element, not just button.
        onClick={() => {
          setCount(count + 1);
        }}
      ></my-button>
      <output>
        Count tracked in React: <span>{count}</span>
      </output>
    </div>
  );
};

const root = createRoot(document.querySelector("react-root"));
root.render(<MyReactComponent />);
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.