Dark Mode in Web Components is About to Get AWESOME!
Tags: css, webcomponents, html, javascript
Published: 2024-04-17 01:29:05

---
title: Dark Mode in Web Components is About to Get AWESOME!
published: true
description: With some new CSS functions becoming generally available across all browsers, working with "dark mode" in web components is about to get a huge improvement.
tags: #css #webcomponents #html #javascript
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2024-04-11 01:16 +0000
---

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.

{% codepen https://codepen.io/break-stuff/pen/YzMvzVY default-tab=css,result %}

> ***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. 

{% codepen https://codepen.io/break-stuff/pen/poBKoLv default-tab=css,result %}

## 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.

{% codepen https://codepen.io/break-stuff/pen/zYXLOVg default-tab=css,result %}

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

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

## 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](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme) 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.

{% codepen https://codepen.io/break-stuff/pen/ZEZjEEZ default-tab=css,result %}

## 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!

{% codepen https://codepen.io/break-stuff/pen/gOyjOpX default-tab=css,result %}

## 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.

{% codepen https://codepen.io/break-stuff/pen/qBwMNoN default-tab=css,result %}

## 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](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/light-dark#browser_compatibility) and [caniuse.com](https://caniuse.com/?search=light-dark) are not accurate. These work in both _Edge_ and _Opera_.

![screenshot of MDN docs where it shows browser incompatibility for Edge and Opera](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ut2d42kjzr6u6pdyd9ee.png)

## 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.