New Dec 16, 2024

React 19 and Web Component Examples

More Front-end Bloggers All from Frontend Masters Boost RSS Feed View React 19 and Web Component Examples on frontendmasters.com

There is lots of news of React 19 and going stable and now supporting Web Components. Or… “custom elements” I should say, as that refers to the HTML expression of them as <dashed-elements>, which is where the trouble laid. Apparently it was hard for React to know, in JSX, if props should be treated as a property or an attribute. So they’ve just decided this is how it will work:

  • Server Side Rendering: props passed to a custom element will render as attributes if their type is a primitive value like stringnumber, or the value is true. Props with non-primitive types like objectsymbolfunction, or value false will be omitted.
  • Client Side Rendering: props that match a property on the Custom Element instance will be assigned as properties, otherwise they will be assigned as attributes.

That’s enough to pass all the tests at Custom Elements Everywhere, which tracks such things. (And apparently every single framework is now 100% fine. Cool.)

This got me thinking about what this actually means and how I might make use of it. I use both React and Web Components sometimes, but only rarely do I combine them, and the last time I did I had more issues with the Shadow DOM than I did with React doing anything funky.

So here I’ve made a LitElement and rendered it within a React component:

What I was thinking there was… what if I make a <designsystem-button> and need a click handler on it? Turns out that’s not really a problem. You can just slap a React onClick right on it and it’s fine.

<MyCard>
  <p>blah blah</p>
  <!-- this is fine -->
  <designsystem-button onClick={() => {}}></designsystem-button>
</MyCard>

That wasn’t a problem anyway, apparently.

What is a problem is if I want to send in a function from React-land for the Web Component to call. You’d think we could send the function in how LitElement generally wants you to do that like:

<!-- nope -->
<designsystem-button .mySpecialEvent=${specialEvent}>

But nope, JSX really doesn’t like that “dot syntax” and won’t compile.

So you gotta send it in more like this:

<designsystem-button onSpecialEvent={() => mySpecialEvent()}

Then in order to “call” that event, you “dispatch” and event named properly. Like:

this.dispatchEvent(new CustomEvent("SpecialEvent", { bubbles: true }));

Here’s that with a “raw” Web Component:

I took that idea from Jared White’s article Oh Happy Day! React Finally Speaks Web Components. Where he’s got some other examples. Another is passing in a “complex object” which is one of those things that would have been impossible in React 18 and under apparently, and now we can do:

Scroll to top