Web Components in Style
Tags: webdev, javascript, css
Published: 2021-03-04 22:40:37

Web Components are really easy to style. You can share styles between them at nearly zero cost, and they can still be styled from outside. They are easy to set up and progressively enhance. There are a throng of frameworks that use Web Components, and if you got into one, you'd know all this naturally. But it's really hard to understand coming from React, Vue, Angular, etc. So let's talk about it.

### Baseline

Web Components are probably the most misunderstood technology right now on the web. It's no one's fault really, the tech is in an awkward place. The industry is caught in a React fever dream, and if not React, then surely Vue, and if not Vue then I guess Angular? All of these frameworks work in their own eco-system. And it's really hard to see what's going on outside of them.

Web Components are about bringing everyone out of the closed-systems to share with each other. It's really easy to make your own walled-garden in tech, and in fact, once you've created it, you have incentives to keep it going. It's a whole other magnitude more difficult to do the work to create standards that everyone can agree on and that build interoperability.

So let's go into what Web Components literally are. I'm obliged to go deep because of the misconceptions out there. There are three main browser features collectively called "Web Components":

### Custom Elements
Being able to make your own elements, your own buttons, your own inputs whatever. The implementation is stupidly simple. You just create a new class extending HTMLElement, and then you register the name.

```
class MyButton extends HTMLElement {
   connectedCallback() {
       super.connectedCallback();
       console.debug("I just appeared on the page!");
   }
}

customElements.register('my-button', MyButton);
```

Et voila you can use `<my-button>` anywhere in your HTML. Cool. BTW, you can use it in React and Vue also. It just works. Yes, we have to run JavaScript, but it's easy for this to be progressively enhanced because the browser treats it like a DIV until the javascript is loaded. You can still style it from the outside.

This implementation of components is about the most straightforward, simple thing you could think of. It's wicked fast because it's using the browser's native object system already, and it's completely full-featured. Also, when you inspect it in the browser, you see it, not some weird `<div class="rg84823">`, not some huge pile of indecipherable elements. Just `<my-button>`.

### HTML Templates
HTML Templates is a way to define fragments of HTML in the DOM without them having to actually run on the page. This lets you do declarative things without having to use JavaScript.

### Shadow DOM
The Shadow DOM is a way of encapsulating and hiding chunks of HTML. Even though `<my-button>` looks like a single element, it can have lots of sub-elements in its Shadow DOM. Just like the `<select>` element has its own inaccessible sub-elements like the dropdown arrow, your Custom Element can have its own little world.

Yeah, it's kind of a mind-fudge. Because you're very used to the DOM tree as being, well a tree. Shadow DOM turns it into a hyper-tree. The nodes can have their own sub-trees off the main tree. That has a cost, mentally. And, honestly, any good developer will naturally want to turn off their brain here because the complexity doesn't seem to have an immediate payoff. But rather than giving up on the concept of Web Components entirely, let's first remember that we don't have to use Shadow DOM to use Custom Elements, and secondly, maybe we can keep trekking on over the conceptual hill, and see what's on the other side.

One of the first things you'll find is that it lets you control how CSS affects the inner-workings of your component. This allows you to shield it from the mess above. Specifically, components become a boundary of the cascade, or in other words, the CSS for your component becomes scoped to it.

There are multiple ways to pierce in and control the style within a component. The easiest, when you are writing the component is to have shared styles. This is a set of CSS styles that components all rely on, a style library. The browser caches it, but gives it to each component. In LitElement you'd do something like:

```
const buttonStyles = css`
  .icon { width: 32px; vertical-align: middle }
`;

class MyButton extends LitElement {
  static styles = [buttonStyles, myStyles];
}

class YourButton extends LitElement {
  static styles = [buttonStyles, yourStyles];
}
```

MyButton and YourButton will both use `buttonStyles`, and whatever else they want, without being changed by the CSS coming from above them.

Another is CSS variables, which if you aren't using, you really should. Components get the CSS variables from above them in the tree. It's common to define and publish with your component variables they support like `--my-button-color`. It becomes simple to change it from above.

We've also got CSS Parts, which lets the component author define pieces to alter.

And finally, since it's a simple JavaScript class, you can extend whatever element you want and hand it new styles.

With these systems, you'll find CSS to be much, much easier to manage. You are naturally pushed towards styling components separately, vs layout, utility, page-elements, etc. You'll find you aren't nesting nearly as much. And generally, you'll find it much easier to organize your styles. I don't even use sass/scss anymore, because I just don't need it.

### Frameworks

Let's talk about the really big misconception. People seem to think Web Components are a competitor to frameworks like React, Vue, Angular, etc. NO! Web Components build a path for these frameworks to provide components for you. Ideally, as an end developer, you would never have to worry about Custom Elements or ShadowDOM except to understand some of the details of styling and encapsulation.

A lot of frameworks are doing this, but not the popular big three, who each have a vested interest in keeping themselves closed off. [Check out the many ways to make a webcomponent](https://webcomponents.dev/blog/all-the-ways-to-make-a-web-component/), all of these frameworks have different strategies and systems, but all of them can be used anywhere, not only in their own garden.

Yes, you can use Web Components in a zero-dependency way, and that's a great option for things like date pickers or very specific one-offs. But it's not the main way you're supposed to consume or even create Web Components. It's just one of many options in an ever-expanding, open system.

Please ask me anything, I'll do my best to help: [@deadwisdom](http://twitter.com/deadwisdom)