Skip to main content
A Frehner Site

More Shadow DOM uses in component libraries

Shadow Roots #

Since the inception of web components, it seems there has always been sort of a love-hate relationship with the shadow root concept and how it isolates the DOM and styling from the rest of the document. This article written by Nolan Lawson does a good job of breaking down the pros and cons of such isolation, and additionally there has been a lot of work to "poke holes" in the isolation barrier through careful API designs such as shadow parts.

Standard Benefits #

When building a component library in {framework of choice here, e.g. React}, it's common to see users of the library reach into the "internals" of the component and make the changes that they want -- even if you hash your class names, or add ESLint rules, or do a myriad of other things to try and prevent this. Unfortunately, this also affects the ability to quickly scale out changes to the component library; despite these pieces not officially being a part of your "public API", the users of the library have come to depend on this ability, and it is frequently considered a "breaking change" for you to change what you thought of as private implementation details of your component, as a relevant XKCD comic demonstrates.

This becomes one of the major upsides to using web components with shadow roots; it's now much harder for devs to actually gain access to the internals.

Extended Benefits #

Additionally, I've been reflecting on other benefits of using web components & shadow DOM for a component library:

Hiding Progressive Enhancements #

One of the nicest things to come out of DOM-land lately is Customizable Select. The only sad part about this new feature is that it's going to take time for the browser support to be stable across all the browsers that a given team has to support. In this case, you either wait until you have full browser support, or you progressively enhance the feature so that newer browsers get the newer experience and older browsers have a graceful fallback.

If you choose to progressively enhance your library's Select component, hiding the dual implementations in the shadow root is a great way to preserve the quality of both experiences; it's common for devs to be on the latest-and-greatest versions of their browsers, so it could be that they neglect to account for the customized fallback behavior on older browsers.

Origin Trials #

In a similar vein, there are other new things coming to the DOM, such as Customizable Combobox. Currently, such a feature isn't even a standard yet, but we can still play with it if we choose to participate in an origin trial.

Back when our component library was written in React, someone could have easily broken the origin trial implementation without knowing, since even developers with the latest and greatest would likely have not known how to test out that version of the component. But now I feel safe in the idea of playing with origin trials safely and giving early feedback on these new proposals.

Contextual Design #

One of the things we're trying out in the latest iteration of our component library is automatic design changes depending on the context a component finds itself in. For example, it's common to have some sort of variant property on a component to slightly tweak the look of it, such as variant="primary", variant="secondary", etc.

But what if we could automatically apply the correct variant for you in the correct context? What if a Banner at the top of a Page component automatically looked differently than a Banner inside of a Card / Section component? What if we enforced that primary Button of a page was always variant="primary", to ensure the user experience is consistent across all areas of our app?

It's an interesting idea, and one we're trying out to see if we can unify our UX across all parts of our app, including externally-developed code (through an app store). With the shadow root hiding the implementation details, we're empowered to enforce these rules automatically without chances of deviation. Now, instead of teams customizing components in ways that the design language never intended, they're blocked and come to us asking how to do it -- which is exactly what we want to happen! We can collaborate on a solution, or provide better alternatives.

Conclusion #

It'll be interesting to see how this all plays out. Ultimately, I'm excited about the power that web components and shadow dom give us.