DEV Community

Creating dynamic themes with React & TailwindCSS

Laurence Davies on April 19, 2020

Adding themes is not usually the first thing you'd think about when starting a new project, but what if it was really simple to set up? Imagine liv...
Collapse
 
fractal profile image
Fractal

Great article!! This helped me implement a similar system in Svelte. However, I noticed that any box-shadows are removed when applyTheme() runs. Do you have any idea how I might get around this issue?

Collapse
 
kevinast profile image
Kevin Bridges

Thanks for your article and insight ... very good information!

I am a new tailwind user. In my learning quest, I just published a color theming utility called tw-themes that is in-line with your article.

You can find the docs here: tw-themes.js.org/

It promotes dynamic color themes that are selectable at run-time. The best part is it automates your dark-mode through "shade inversion"!

When you have time, I would be curious of your thoughts.

Collapse
 
sahildhimandesigner profile image
Sahil Dhiman

Hello Laurence
I have implemented the code as per above instruction. But, when I am clicking on button to change the dark mode getting some error. Like : TypeError: Cannot read property 'primary' of undefined
Can you please help me that what are the reason behind of this?

Collapse
 
ohitslaurence profile image
Laurence Davies

Hi Sahil,
So I was just looking at the above code, and I can see where it might be going wrong. So if you look for the line where I say Now we can create our dark theme, and export it., I don't say explicitly where to export that file to. So what you need to do is go to themes/index.ts, and add the dark theme in.

// src/themes/index.ts
import base from './base';
import dark from './dark'; // add this
import { IThemes } from './utils';

/**
 * The default theme to load
 */
export const DEFAULT_THEME: string = 'base';

export const themes: IThemes = {
  base,
  dark, // add this
};

Now, when the applyTheme function looks at your exported themes, it will be able to find your dark theme and apply it. Hope that helps!

Collapse
 
javierriveros profile image
Javier Riveros

Great article, I have a question, It is necessary to apply the theme every time the state changes?, Wouldn't it lead to performance issues?

Collapse
 
ohitslaurence profile image
Laurence Davies • Edited

Thanks man! Great question, so the short answer is no. It's not running every time the state updates, but rather every time the theme state variable updates. If you take a look our useEffect hook, we have the theme variable as an effect dependency. This means it will only run the first time we set that variable (in the useState hook), and then when we make changes to it (through the setTheme function). It's why hooks are so awesome, no hidden side-effects.

If this were not just an example app, I would create a theme context provider and use a hook to run the applyTheme the very first time the app loads only. All subsequent changes would be done directly through an action of some sorts. I'm hoping to show that in a follow-up post :)

Collapse
 
javierriveros profile image
Javier Riveros

Oh, thank you for the explanation, I wasn't looking at the dependency array. Now it is clearer.

Collapse
 
dsidev profile image
DSI Developer

Excellent article

Collapse
 
pedromiotti profile image
Pedro Miotti Arribamar

You helped me a lot! Thanks for taking the time to write the article

Collapse
 
laurenmwright profile image
laurenmwright • Edited

Extremely helpful - the only issue I have encountered is that when my postcss script runs and generates App.css, the script is not generating my theme styles (--color-primary) for most prefixes.

For example, it builds text-primary but does not build bg-primary.

When I downgrade my postcss/tailwind dependencies to the version used in this tutorial, i get the bg-primary classes in the App.css.

Why would the latest postcss not build all my themed styles?

Collapse
 
laurenmwright profile image
laurenmwright

I figured it out - Tailwind v2+ has a Just In Time mode so it will only generate styles if the builder reads them ahead of time. I was using a value loaded from state in the classNames so it couldn't read it.

From what I can tell, you have a couple of options if you want to references your style themes from variables :

  1. inject a bunch of the tailwind classnames into a static field and just not display it
  2. avoid using tailwind for any styles you want to apply based on a state value but using inline styles or some sort of styled component.

Not great IMO

Collapse
 
neginbasiri profile image
Negin Basiri

How do you support live css watch in this setup?

Collapse
 
tramsi profile image
Tramsi

Great article

Collapse
 
andygr1n1 profile image
Andrew

This is powerfull, my respect

Collapse
 
tancredesimonin profile image
tancredesimonin

you made my day, thank you so much <3

Collapse
 
hood profile image
Andrea Cappuccio

Great article, really clean implementation and very clear steps.

Collapse
 
vkboo profile image
tyounami

I was too late to explore the project myself. This article was very helpful to me. Thank you very much! ! Specially registered an account to thank you.