Published on May 3, 2024 (8 months ago)

Facebook just updated its relationship status with web components

Dylan Jhaveri
By Dylan Jhaveri5 min readEngineering

As our friend of the blog, Wes Bos, pointed out the other day, React 19 (beta) added, all the way at the bottom of the announcement, much-awaited support for web components.

I say “much-awaited”, but the truth is a lot of people are not going to care at all about that. There are some, though, like us who really care and have been paying close attention.

At Mux we have not been shy about our fondness for web components over the last few years. It started with building Mux Player on our web components-based player framework Media Chrome (thanks for the kind words about Media Chrome, Joel).

But I want to drive home one point about our fondness for web components. It’s not about some righteous party line, which so many front-end tooling debates devolve into. If you came to this post for some juicy nerd drama, turn around because that’s not what we’re here for. Our adoption of web components is purely based on practicality. Nothing more, and nothing less. Is it the best tool for every job? Obviously not. But we believe it is the best tool for the job of building a framework-agnostic video player SDK. We still use React heavily. In fact, we were early adopters of React Server Components and wrote about it in Darius’s widely circulated post.

LinkSo what does this mean for React, actually?

To contrast all the positives about building SDKs on web components, React support has been by far the biggest hurdle to clear for web components projects. Raw web components have always worked in React (it’s just HTML, after all), but the challenge was more about the ergonomics of using web components in a React world.

For example, React developers don't interact directly with HTML elements to do things like add event listeners and call functions. It sort of goes against the declarative nature of React itself.

So although setting up an event listener was possible, like this, it feels very un-React-y:

jsx
function MyComponent () { const ref = useRef(null); const [count, setCount] = useState(0); useEffect(() => { function handleClick () { setCount(count + 1) } if (ref) { ref.addEventListener('click', handleClick); } return () => { ref.removeEventListener('click', handleClick); } }, [ref]); return <my-button ref={ref}>Hello! {count}</my-button> }

Because of this, most maintainers (us included), have chosen to create React-specific wrappers. That works well, but it always felt like a stop-gap. Now that React 19 supports web components directly, you can do things like pass event listeners as React props and React props passed to the element get automatically set as properties on the element. There’s some extra complexity here for web component authors to handle attributes vs. properties. Not all web components will play nice with React from day 1, but at least we have a path forward.

See here, this feels much more React-y:

jsx
function MyComponent () { const [count, setCount] = useState(0); return ( <my-button ref={ref} onClick{() => setCount(count + 1)} > Hello! {count} </my-button> ) }

Internally, all React is doing here is taking the onClick prop and setting up/tearing down the click handler under the hood. Which is basically what React wrappers were doing anyway.

I’m hoping that in 1 or 2 short years from now your average React developer will not be weirded out or averse to using a web component in their React application. And once that feels normal perhaps we can thank those old React wrappers for bringing us joy and then do away with them.

LinkIt still might be a little weird

Event handlers and passing React props into web components is a nice improvement, but I think there’s still one weird thing about web components that doesn’t quite jive with the React way of doing things, and that’s the globally scoped element register.

In any React app, when you use a component, you have to import that component:

jsx
// when MyThing is a react component import MyThing from './components/my-thing'

But that doesn’t exist in the web components world (at least not yet). When you use <my-button> in a React component, you don’t have to explicitly import my-button from anywhere inside that file.

jsx
// when my-thing defines a web component is imported it gets registered globally import './components/my-thing'

Web components get imported and registered at the global level. This also means if two different libraries have a component called my-button, you can’t use both of them. This will certainly be a little weird for React developers to get used to. It also might change with Scope Custom Element Registries in the future.

LinkDon’t sleep on Web Awesome, either

One other web components topic caught my eye last week. Shoelace, one of the premier web components projects, launched a Kickstarter project for Web Awesome after being acquired by Font Awesome. With a modest goal of $30,000, the campaign gained the pledges of 6,725 backers for a total of $723,004, nearly 25x the original goal. And I don’t think that’s all hype – I think there’s a reliable signal here that developers want a stable set of tools, built on browser standards.

LinkLet’s see how things pan out

That’s all for now, we’ll see how things pan out. I, for one, am happy to see the React ecosystem moving in this direction. And I believe the general frontend ecosystem is criminally under-indexed on web components. All web application developers can benefit by moving parts of their applications away from framework-specific patterns and more towards browser-level standards. Frameworks will come and go, so as developers and maintainers we build against them at our own risk. Browser standards tend to come, albeit slowly, and then rarely disappear after that.

Right now the plan is to wait and see. In the short term, we’ll keep maintaining our React wrappers. It’s all going to depend on if React developers, as a general population, start embracing web components and start feeling comfortable using them in their applications. We want our component libraries to feel great and idiomatic wherever they’re used…and we hope one day soon that could just mean web components.

Written By

Dylan Jhaveri

Software Engineer and cold water surfer. Previously startup co-founder. Trying to find the best cheeseburger in San Francisco.

Leave your wallet where it is

No credit card required to get started.