Dark theme with Stitches

Integrate dark theme support with Stitches on Gatsby.

After tinkering a bit with Stitches, I am very excited to see the improvements in DX, variant-first support, and performance in the CSS-in-JS space! Definitely give their documentation a peruse to see all the brilliance being done.

While exploring this library, I found a small theming gotcha when integrating it with my Gatsby static site. If you are curious about using Stitches with Gatsby supporting a dark theme, read on to see my current solution.

Switching to Stitches

As an experiment, I decided to swap out styled-component with @stitches/react to test out Stitches' developer experience and performance. I was also curious about the effort of migration and what was required to support my site's dark theme.

Swapping components was very straightforward, especially with the help of the CSS-in-JS VS Code plugin. My initial reason for authoring my components using the tagged template literal method was to maintain closer compatibility with CSS. However, object styles are well supported the JS community and a versatile structure for storing styles.

A small plus, object styles are also a tad faster than runtime-parsed template strings. They also work better with libraries that support a typed interface (ex: vanilla-extract, Stitches).

Theming with Stitches in Gatsby

Back to the theming problem! The only other migration step was to update the theming layer. I followed the dark theme pattern well explained and shared from Josh Comaeu – thanks Josh! Using the Stitches getCssString helper, I simplifed my code a good bit. Stitches handles the addition of CSS custom properties based on your theme configuration, allowing me to remove the chunk of code that was manually handling this step.

Here is the final required code used in the site's SRR step:

This is a slight variation of Josh's strategy and solution outlined in the Stitches tutorial. For some extra reading, I encourage checking out Josh's full dark theme solution or digging into the source code example!

Final adjustments

The only other modification is updating the ThemeContext to toggle the appropriate className on the root document element:

When running in development, the site may initially load in the default light mode. The page adds the dark theme CSS custom properties when using darkTheme.className in ThemeContext.tsx. I'm not a Stitches pro, but looking at the current source, it appears this occurs in the className getter function which triggers a stylesheet update. Note that this may change in the future, as Stitches is in beta.

When built for production, Gatsby statically generates each page which all include the Theme Context. The Theme Context adds the dark theme variables to the site when run and rendered as part of the static build. This avoids the flash of the light theme on the initial page load.


This was a pretty niche problem. I thought I'd share my current solution since I hadn't discovered one myself in the docs or example repos. Happy styling with Stitches, and a big thanks to the team's awesome work. Looking forward to seeing Stitches evolve even more. 🧶🪡

Subscribe to the newsletter

Be the first to know when I post something new! Thoughts about code, design, startups and other interesting things.

© 2022 Sam Rose
All Rights Reserved.