I just want to be alone in the dark….

Samantha Betts
DAZN Engineering
Published in
6 min readMay 20, 2022

This is my first ever technical (kind of) blog post — be gentle with me!

I felt the need to write this after taking on what I thought was a fairly straightforward challenge, to create a reusable color theme with light/dark modes using Create-React-App, Material UI and Typescript, for use with internal company apps at DAZN.

Firstly, let me just show you the old theme we were using (boring right?) 😝

In my team (DX) we like things to be bright and fun, so I was tasked with updating this along with creating some nice reusable components.

What I wanted: A custom colour theme which could be toggled between light and dark modes, with a fun react toggle and custom palettes for BOTH the light and dark modes.

Does MUI want me to do this easily? No.

It seems that regardless of trying to specify custom colors for ‘dark’ in MUI palette, it always uses its own default dark palette. So actually toggling between light and dark is a simple enough implementation, but of course I wanted to be difficult and have my very own special custom dark mode, and I don’t give up easily 😤.

Before I tell you how I actually did it in the end, I want to give a disclaimer that I am not guaranteeing this will work for you! For my specific use case this was the solution, and I hope it might help someone else! But I did try loads of other different methods which I saw working code sandbox examples of, but they didn’t work for me. So there is for sure many different approaches to this, and after reading the entirety of StackOverflow, I know for sure that I am not the only one who has had sleepless nights over this.

Let’s dive straight in!

Firstly I created my theme.ts which looks something like this:

All the usual suspects are here, responsive font sizes and create theme from MUI and then typography and CssBaseline imported in (I am using custom fonts here as we have our very own special DAZN fonts which I’m obsessed with, but this of course has nothing to do with the light or dark themes — so just ignore if you don’t have your own fancy fonts. 😝)

I have created a Global Theme, this is for all the stuff that light and dark themes will share, so not to have to define these multiple times. I then have my light and dark below which both use the global theme and are exported separately.

A little heads up:
-
Text needs to have ‘primary’ and ‘secondary’ colours set. As you can see I have these set to the same colour, both white for dark mode and both black for light mode. This was after many google searches and moments of despair trying to find out why some text was responsive to the theme change and some wasn’t. Basically MUI components use the ‘secondary’ text color attribute for things like labels, so if you don’t set this in your theme, some of your text will always be dark and unreadable when in dark mode.

Theme Provider and creating context:

Next up I created a file called ThemeContextProvider.tsx — this is where I built the component which will wrap around my app.

For this I needed to import ThemeProvider and useMediaQuery from MUI, both the light and dark themes from my theme.ts and a useLocalStorage hook which I created in separate file. The storage hook is so that when my user chooses between light or dark mode, their browser will remember their preference and always reload in their chosen theme. You can read more about how to create this hook here (but I have also included my code for this in the second image below if you just want to copy me — after all copying code you find online is what developers do right? 😎)

ThemeContextProvider.tsx
useLocalStorage.tsx

So what is actually happening here?
We are creating two contexts, ThemeContext and ModeContext.
Theme is changing the theme and Mode is changing the actual toogle button (will explain that more later).
These could probably be combined somehow into one context but I’m just a Junior Developer and I managed to get it to work this way so that is how it shall stay for now 😅.

I am then using useMediaQuery and a switch case to basically answer the question ‘what is the current Theme Mode? Is it Dark?’ — if the answer is yes, the toggle knows to set the theme to light, if no, then set it to dark.
Smart toggle 🤓.
Then our useLocalStorage hook is in there to remember the chosen theme.

You’ve probably noticed I am also using StyledEngineProvider from MUI. This is because my themes sit inside a library of custom reusable components (which I also made 😌) and I discovered that when exporting them into other projects some of my custom styling was overridden. The StyledEngineProvider solved this issue, it removes the need to have to use !important by sorting out the CSS injection order. You can read more about this here.

After that, I render the ThemeContext.Provider passing it the toggleTheme switch case as the value. Then our ModeContext.Provider passing that our themeMode with a strict equality operator as the value has to be a boolean, either ‘light’ or ‘dark’.

Finally I have the MUI ThemeProvider where I can render my custom themes, so I tell it that the theme again is a boolean of either LightTheme or DarkTheme depending on what the toggle tells it to be! 🌚🌞

Now we need a cool toggle button on the front end!

For this I chose to use a react toggle, it’s really fun and pretty so if you want to be cool like me you can install it from here.

It is a fairly simple imentation (but I won’t tell you how many days it took me to get it to work 😆).

ThemeToggle.tsx

So here I am importing my ThemeContext and ModeContext. The ModeContext (as I mentioned earlier), is changing the toggle button — so when clicked(checked) it knows to be a moon🌙 if were in dark mode and a sun☀️ when we change to light mode. The setMode is then using the ThemeContext to actually switch the theme.

So now everything has come together nicely to make my cool toggle button switch between my custom light and dark themes. WIN! 🏆

Now I can head to my index.ts and wrap my app with the ThemeContextProvider function, then render the ThemeToggle wherever I want it to be! (NavBar is the logical place).

index.tsx
NavBar.tsx

Remember at the start when I showed you the boring old theme?
WELL LOOK AT IT NOW!

And a little GIF of the toggle doing its thing 🌈 🎨

--

--