Watch Out! Challenges Using Web Components in Angular and React

Dan Bellinski
84.51°
Published in
4 min readMar 31, 2020

By Dan Bellinski, 84.51° Application Developer

Challenge climbing moutain
Photo by Joshua Earle on Unsplash

84.51°’s design system, Meridian, is built using StencilJS. We covered why we chose to use StencilJS to create web components in a previous article. The web components built by StencilJS are used by both Angular and React applications in production. For the most part, our experience with web components has been very positive but there have been a few snags along the way which we’ll cover in this article. I’ll also share how we got around them at the end!

Web Components in Angular

Angular’s support for web components is pretty good — but not perfect. Angular has their own web component library (Angular Elements) so support in Angular is essential. With a line of code, you can include web components in your Angular app by adding the CUSTOM_ELEMENTS_SCHEMA to your App Module.

Adding Web Component Support to Angular in App Module

One line of code and you’re off and running — great, right?! Unfortunately, including the CUSTOM_ELEMENTS_SCHEMA became a sore subject with our developers.

What is wrong with CUSTOM_ELEMENTS_SCHEMA?

When you provide this schema to Angular, it will ignore any elements it doesn’t recognize (your web components) on build and serve and let the browser try to render them. What we came to realize is that Angular will ignore any element it doesn’t recognize, not just your web components. This resulted in a scenario occurring twice that cost a developer their afternoon.

  1. A developer, Jill, created an Angular component (e.g. <demo-ng-component> intending it to be used in another module but, on accident, didn’t export it from the feature module that declared it. In short, this meant the component couldn’t be used by another module.
  2. Jill added the demo-ng-component to another component’s template in a different module in order to use it.
  3. Jill started the app, went to the page they expected to see demo-ng-component, but nothing rendered.
  4. Checking the console for errors, there were none! Jill spent a few hours confused, asked for help, and eventually we discovered that the demo-ng-component wasn’t exported.

What was different about this scenario than normal Angular development? Normally when you try to use a component that isn’t properly provided, a quick attempt to build or run the app results in the error below:

Uncaught Error: Template parse errors: ‘demo-ng-component’ is not a known element:1. If ‘demo-ng-component’ is an Angular component, then verify that it is part of this module.2. To allow any element add ‘NO_ERRORS_SCHEMA’ to the ‘@NgModule.schemas’ of this component.

When seeing that error, the developer immediately realizes they missed an import or export somewhere. However this time, Angular didn’t throw any build-time or run-time errors. Angular didn’t recognize demo-ng-component but because we had set the CUSTOM_ELEMENTS_SCHEMA set, it was happy to ignore it.

Ideally, Angular should have the ability to configure the CUSTOM_ELEMENTS_SCHEMA to recognize what is intended to be a web component (don’t throw errors) versus what is a mis-configured Angular component (throw errors). One possible way for Angular to implement that is the component prefix — i.e. only allow unknown elements starting with “mds-”. Unfortunately that functionality doesn’t exist.

Web Components in React

React’s support for custom elements is just okay. The most painful gap we experienced was React’s inability to bind to custom events from web components.

How to Bind to Custom Events in React?

Rather than bind to the web component’s custom event in the template, like you would using a native React component:

<my-web-component (onMyCustomEvent)={respondToEvent}></my-web-component>

You have to instead use JavaScript to add an event listener to the web component to handle the custom event:

document.querySelector(‘my-web-component’).addEventListener(‘myCustomEvent’, () => { // handle event})

While passable, this leads to ugly code by separating the event handling from the use of the component and puts more work on the developers to use the web component.

Web Component Properties

The other challenge we had is React’s recognition of web component properties. Let’s say we created a property on our web component called ‘iconOnly’. In Angular, we can use that property like so:

<my-web-component iconOnly="true"></my-web-component>

In React, trying that same code fails to set the property correctly. Instead, it will only recognize the property in all lowercase, like so:

<my-web-component icononly="true"></my-web-component>

In order to reduce confusion for our users and simplify our Design System documentation site, we ended up naming all of our web component properties using lowercase so the code usage is the same no matter what framework you’re using.

Other Gaps

There are a few other issues with React’s web component support that we haven’t run into. A great resource to identify gaps with web component support for React, or any other modern JS framework, is Custom Elements Everywhere. They have an automated suite of tests that verifies the level of support for the Custom Elements specifications.

Conclusion — How We Solved for These Challenges

None of the challenges we faced in Angular and React were show stoppers to use web components. I’d still recommend using them as framework support for web components will only improve over time.

That being said, we were fortunate that StencilJS open sourced their output target plugins for Angular and React shortly after we released Meridian. The output targets simply take your StencilJS web components and add a native Angular and React wrapper component around them. These allow your web components to be used just like any other native Angular or React component, removing the need to use CUSTOM_ELEMENTS_SCHEMA (Angular) or to add manual event listeners with JavaScript (React).

After adding these new output targets and switching our users to the native components, we were met with gratitude from our consuming developers!

--

--

Dan Bellinski
84.51°
Editor for

Director, Software Engineering @ 84.51°. Passionate for all things web and mobile development!