How to Create a Theme Switcher with Fresh
5/23/2023, 1:42:08 PM

Being able to customize your Theme can be a huge user experience upgrade to any website. While some websites use a default Dark Theme, the majority of the internet still sticks to creating content in Light Mode as default (and sometimes the only option).
However, if you have tried to do this on your own using Fresh before, you might have run into a problem... or many. In this blog post, I'll explain how I've created my theme, what issues I've faced, and how I've solved them.
What is Fresh?
Fresh is the official framework to create web apps using Deno's Javascript runtime. It features no build step, zero-config, Typescript support out-of-the-box, JIT-rendering, and uses the Island design architecture (more about this in a minute). The premise here is very simple: Single Page Applications rely heavily on the client's devices to build the content of webpages and that creates overhead that impacts performance. Fresh, just like Remix (and to some extent NextJS), aims to move all the rendering back to the server, serving exclusively static HTML pages, hydrating any interactivity only when/if necessary. While that's amazing for Lighthouse performance, it comes with its own sets of drawbacks (more on that in the next post).
Fresh uses Preact under the hood to compile the JSX/TSX files into static HTML that is then sent to the client. If you have experience with React or Solid, you shouldn't have any trouble adapting, especially if you have experience building Full Stack projects.
Creating A Theme Switcher
Let's create a very simple Theme Switcher:
This creates a radio input that has Dark
selected by default and allows you to toggle between modes. Switching themes will toggle between the Light and the Dark versions of the theme for this blog, now let's make sure we can save the changes when the user clicks either input. Feel free to replace the values of --base-color
, --neutral-color
, and --accent-color
with the values for your theme.
We have added a reference to the useEffect()
to avoid having it saving the current theme
to localStorage
on the first render.
What the useEffect()
does, in order:
Runs on start, checks if there is a theme saved (if not,
savedTheme
will benull
), and sets the current theme as thesavedTheme
, if they are different, then stops (remember thatuseEffect()
is using thetheme
as a dependency so not returning here would cause an infinite loop!).After setting the
theme
equal tolocalStorage
'ssavedTheme
is the same as thetheme
, it will skip the firstif
check and negate theisInitialMount
value and stop.(Optional) If the
theme
is updated, it will skip bothif
checks, save the theme tolocalStorage
, and applies it.
This website uses an improved version of the same Theme Switcher created in this post, which you can check the source code for right here.
What's next?
If you have been following along, you might have noticed a few issues with it, like flickering on first load or the inability to check for user preferences. Let's address those problems on those on the next blog post.