2021 April 18
Icons8 Team on Unsplash

Dynamic Themes with GatsbyJS

Icons8 Team on Unsplash

I was bored this Saturday and decided to try something. I wasn't exactly sure how possible it would be since GatsbyJS generates static pages. Naively I thought whatever gets thrown into gatsby-config.js would be static as well... The answer is still technically yes, with Styled Components, color themes are dynamically toggled by withTheme() using what is statically set. However, it's possible to interupt that process and do something else.

To clarify what I mean about "themes", in this context I do not mean what Gatsby refers to as "Themes". This post strictly shows you how it's possible to change the color theme. However, this has opened the door to some interesting possibilities and I'm certain this is possible with other JS-in-CSS methods. Personally, I'm content with using Styled Components for my personal site so this example is using this particular plugin.

Example Using Styled Components

After following the instructions for using Styled Components in GatsbyJS, I created a new file called customThemes.js and edited GlobalStyles.js slightly.

Before I get ahead of myself, here is how I have personallly written my lightTheme and darkTheme for this site:

In the gatsby-config.js file, we import the above themes for gatsby-styled-components-dark-mode to handle:

Adding Custom Themes

Within the same folder as themes.js add a new file. Take note that I am also importing the default themes. You'll see that there is a new object called halloween 🎃 with it's own light and dark themes. Also wrritten in this file are two functions setTheme and updateCSSRoot. Only setTheme will only be exportable and will be used in GlobalStyles.js:

Modifying the Global Stylesheet

We import setTheme() and add that to :root.

Each time the theme is toggled by the useStyledDarkMode() hook, it actively refreshes the global stylesheet on client-side. setTheme() interupts the default themes from getting used and checks the month. If it happens to be October, it will instead replace our themes with the custom halloween themes, returning the required CSS variables that controls all of our components' styles.

As a bonus, it's also possible with replacing fonts. So if I wanted to, I can replace the current font with something "spooky" (which I'm planning to 👻). And since this is essentially Sass, you can throw in custom functions as well. Heck, you could even replace the entire stylesheet with an alternative one. All of that and it doesn't require the user to hard refresh the page.

Result

Here's a working example where I set the halloween theme to appear at exactly 8:30 AM. You'll see my standard dark theme have orange borders and my standard light theme have a light purple hue. This is a very rough first example, but I'm definitely going to sprinkle in a bunch of hidden things to appear throughout the year!

programmatic theme example

Thoughts

I don't believe you can update the entire site with a completely different "Gatsby Theme" because these are used during page generation, but it doesn't have to stop here. For more complex than styles, such as changing the functionality of a site, I recommend using wrapRootElement for gatsby-ssr.js and gatsby-browser.js. In the end, it's still React!

Also something great about using Gatsby Cloud, I was able to test this quickly without having to publish this live by simply creating a pull request which triggered a separate build for me and reports to the pull request if successful.

gatsby cloud screenshot

pull request screenshot

Copyright © 2021. Jake Wantulok