DEV Community

Burton Smith
Burton Smith

Posted on

Dark Mode in Web Components is About to Get AWESOME!

You may think the title of this article is hyperbole, but I assure you what is coming for managing "dark mode" in web components is about to get awesome. Before we get into the solutions, let's talk about the problem.

The Problem

When working with light and dark mode themes today we typically have two approaches to solving the problem - using media queries and using a theme switcher/toggle.

Using Media Queries

The first is with the prefers-color-scheme media query and CSS custom properties. Colors and styles are defined one way for "light mode" and again within a media query for "dark mode".

This method allows us to provide styles based on the user's system preferences, but leads to large CSS files and makes it difficult to manage the theme globally or at a component level (for example, if we wanted to create an "inverted" nav bar) because it's difficult to force the color scheme to change.

NOTE: In addition to the many benefits of CSS custom properties, it is important to note that they are inheritable across shadow roots, which makes them fantastic tools for managing design tokens in a web component library.

Using a Theme Switcher

Another scenario is when sites provide a theme toggle so users can choose between light and dark modes, but also allow it to fall back to user preferences if one isn't selected. This usually requires defining styles scoped to "light-mode" and "dark-mode" class names and some JavaScript to check the user's system preferences to set the user hasn't been specified.

This can introduce FOWC - Flash of Wrongly-styled Content (yes, I just made that up) - while the browser loads and parses the JavaScript. It also makes it very inconvenient to understand what "mode" our project is in within the shadow DOM.

Enter light-dark() CSS Function

light-dark() is a new CSS color function that allows us to define light and dark mode colors in a single property without needing to redefine our properties in a media query or alternative class name. With this new function, we can simplify the implementation by not having to define the style in two different places.

This example provides the same functionality as the first example with the media query, but with significantly less code and is much easier to maintain.

If we use a design token system, this can be used with CSS custom properties (variables) to create other CSS custom properties.



--button-bg-color: light-dark(var(--light-color), var(--dark-color));

Enter fullscreen mode Exit fullscreen mode




Using color-scheme

If we want to add the theme switcher capability, we can do so with just a few lines of CSS. The CSS color-scheme property allows us to dictate to the browser which color scheme to use. This is nice because it not only uses the light and dark colors defined in the light-dark() function but also the browser's native light and dark mode colors.

Composing Web Components

Let's add a web component into the mix and see what happens. In this example, the web component requires different colors than the global button colors we originally defined.

One of the best parts about this is that the color-scheme value is inheritable across the shadow root, meaning the code in our shadow DOM can be context-aware of the color scheme!

Creating Themable Components

Not only can the components be aware of the color scheme, but we can also dictate it based on the component's API.

Considerations

At the time of writing this article, the light-dark() function is in the beta release of Safari. It also looks like the MDN browser compatibility info and caniuse.com are not accurate. These work in both Edge and Opera.

screenshot of MDN docs where it shows browser incompatibility for Edge and Opera

Conclusion

With these new CSS features, our ability to style content in and outside our web components will significantly improve. We can get more features than we have today with much less code that is more performant and compatible with the native browser APIs.

Top comments (5)

Collapse
 
btopro profile image
Bryan Ollendyke
Collapse
 
stuffbreaker profile image
Burton Smith

Nice! Thank you!

Collapse
 
karenpayneoregon profile image
Karen Payne

Well written, thanks for taking the time to present this.

Collapse
 
danbailey profile image
Dan Bailey

I'm definitely liking the structure/formatting for light-dark, but support for it isn't great. Yet.

Collapse
 
stuffbreaker profile image
Burton Smith

Unfortunately, that's not accurate (check out the "Considerations" section in this article). We're just waiting on Safari and it's already on its way.