CSS-in-JS with StencilJs

Justin Palmer
2 min readJan 31, 2020

--

While working as an engineer on a team building a design system, the decision to go with web components as one of the code elements offered was made. After discussions, research, and POC’s, we decided to go with StencilJs as the framework to build the web components.

The Problem with the Shadow DOM

While StencilJs is great and most things worked fine, there was one main issue that plagues the ecosystem (an issue with web components in general). This issue is overriding styles, due to how the shadow DOM works. While CSS custom properties work well for allowing users to dynamically theme components for certain things such as primary colors, the ease of use falls apart once you want to provide stronger theming capabilities and style overrides. If you’ve ever used a library like Material-UI, then you’ll immediately feel the difference in developer experience in regards to theming.

CSS-in-JS to the rescue

Luckily these issues can be solved easily with a CSS-in-JS implementation. As we were using Stencil for our framework, I started on a solution for Stencil that would need to meet several requirements:

  • Dynamic runtime theming
  • Support strong style override functionality
  • Performant

Solutions

While attempting to come up with solutions to meet all of the requirements, we tried several different implementations to see which would work best, both from a developer experience standpoint as well as a performance one. Some of the solutions that were tried were:

  • A StyleHandler render prop
  • A custom property decorator
  • A component factory
  • Observable Services

The Winner!

In the end, the winner was surprisingly the custom property decorator. It not only met all 3 requirements and had great performance, but it also had the best developer experience of the various implementations.

Show me the code already!

Well that’s enough of the boring explanations. Here are some simple code examples to better illustrate the implementation:

Basic:

Dynamic Styling based on Theme property:

Component Style Overrides:

While the other pieces of functionality are interesting themselves, it’s the style override functionality that is probably the most important for the end user of the component library.

Closing Thoughts

The library stencil-css-in-js is now available to be downloaded from npm as well (currently in beta).

In the end, the custom decorator approach works great for the use case of my team, and most likely any case which has the same requirements. That said, we still hope to improve upon the developer experience further in the future with a Styled Components-esque api. This is not currently feasible unfortunately due to limitations with Stencil in large part due to performance reasons; however, if stateful functional components ever become part of the Stencil api, we plan to revisit this as a potentially viable solution.

--

--