40

Looking at Tailwind CSS, it seems that you need to specify specific colors in your classes like this:

<div class="bg-yellow-200 dark:bg-gray-800"></div>

But what if I want to offer 10 different themes that users can choose from in my web app? Like I might have themes like halloween and summer and winter and party etc.

I know that with regular CSS this is very easy done like this:

[data-theme="halloween"] {
    --color-bg: #000;
    --color-body: #757981;
}

<body data-theme="halloween"></div>

And then using Javascript I can change the data-theme property and the theme will change.

But how could I do this with Tailwind CSS? I couldn't find anything in the documentation about this.

3
  • Have you tried the docs? tailwindcss.com/docs/theme Commented Sep 12, 2021 at 11:25
  • 12
    @Quentin I see it only talks about how to configure the default theme not how to add more themes. Commented Sep 12, 2021 at 11:35
  • 2
    Unfortunately it doesn't seem to be as simple as adding themes to the configuration. It seems like this answer might point you in the right direction. It suggests using a plugin to add prefixes to class names which use CSS variables that define the theme. Commented Sep 12, 2021 at 14:59

5 Answers 5

48

I did actually find a solution using CSS variables.

In your CSS file, you can define your styles for each theme like this

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  html[data-theme='default'] {
    --color-esther: 34, 39, 46;
    --color-maximus: 45, 51, 59;
    --color-linx: 55, 62, 71;
  }

  html[data-theme='neon'] {
    --color-esther: 20, 61, 42;
    --color-maximus: 13, 82, 66;
    --color-linx: 20, 82, 11;
  }
}

Then in your tailwind.config.js file you can define them like this

Tailwind version ^3.1

module.exports = {
  theme: {
    colors: {
      esther: 'rgb(var(--color-esther) / <alpha-value>)',
      maximus: 'rgb(var(--color-maximus) / <alpha-value>)',
      linx: 'rgb(var(--color-linx) / <alpha-value>)',
    },
  },
}

Tailwind less than version 3.1

function withOpacity(cssVariable) {
  return ({ opacityValue }) => {
    return opacityValue ? `rgba(var(${cssVariable}), ${opacityValue})` : `rgb(var(${cssVariable}))`
  }
}

module.exports = {
  theme: {
    colors: {
      esther: withOpacity('--color-esther'),
      maximus: withOpacity('--color-maximus'),
      linx: withOpacity('--color-linx'),
    },
  },
}

And in your HTML, you can use these classes like this:

<html lang="en" data-theme="default">
  <body class="bg-esther text-optimus cursor-default"></body>
</html>
Sign up to request clarification or add additional context in comments.

6 Comments

This seems like an awesome solution, but after following your steps I get --color-esther is not defined imgur.com/a/FnkeB3p
@Justin please provide a full code example so I can take a look at it and see what's wrong
@MartinZeltin what sense does it make to add attribute selector in base layer? usually its used for tag selectors only
@Justin I'm guessing you forgot to apply the data-theme="default" HTML attribute
From Tailwind 3.1 you can now entirely remove the withOpacity function and instead use a format string like this primary: 'rgb(var(--color-primary) / <alpha-value>)' tailwindcss.com/blog/…
|
15

tw-colors is a library I wrote to solve this exact problem.

tailwind.config.js

const { createThemes } = require('tw-colors');

   module.exports = {
      content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
      plugins: [
         createThemes({
            halloween: { 
               'primary': 'orange',
               'secondary': 'yellow',
            },
            summer: { 
               'primary': 'pink',
               'secondary': 'red',
            },
            winter: { 
               'primary': 'blue',
               'secondary': 'green',
            },
            party: { 
               'primary': 'steelblue',
               'secondary': 'darkblue',
            },
         })
      ],
   };

use themes like this with class:

<html class='theme-halloween'>
      ...
</html>

Or with data attributes:

<html data-theme='halloween'>
      ...
</html>

Then use tailwind classes as you normally would. A button with the class bg-primary will change color according to the closest theme.

Themes can be switched dynamically with some toggle button or whatever you prefer

Comments

7

There are a couple of plugins that support defining multiple Tailwind themes, and switching between them. I particularly like the thailwindcss-themer plugin because it allows you to:

  • switch themes by simply adding a css class with the name of the theme on any component (usually the top-level component)
  • use CSS classes like you would normally do (e.g. text-primary). This keeps code clean and independent of the plugin (contrary to other plugins, which sometimes require a specific prefix on every CSS class)
  • use variants to further finetune styling, e.g. my-theme:font-bold

Comments

1

Just stumpled upon this question as I am doing the same what I already did a few years ago but couldn't remember anymore. In case anybody comes here again, maybe this answer might be helpful.

In our case, we are building a theme that is applied to 3 different websites but obviously changes colors and fonts, which seems to be the same case the question author has.

For this, tailwind presets can be used. I have one tailwind.preset.js which is basically the default tailwind configuration with all the base colors, spacings etc. For each theme, a separate tailwind.<theme-name>.js is set up that contains the changes and bases itself on the preset.

Example tailwind.theme-one.js:

module.exports = {
  presets: [
    require('./tailwind.preset.js')
  ],
  theme: {
    colors: {
      # color changes go here
    }
  }
}

We have a gulp workflow set up that basically just renders the main scss file once for each theme configuration. On the integrations, the required theme file is being loaded then.

1 Comment

it is not the same use case as the OP had. He wants the user to be able to switch themes at runtime
0

If top answer is not working, you may need to remove commas like this:

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  html[data-theme='default'] {
    --color-esther: 34 39 46;
    --color-maximus: 45 51 59;
    --color-linx: 55 62 71;
  }

  html[data-theme='neon'] {
    --color-esther: 20 61 42;
    --color-maximus: 13 82 66;
    --color-linx: 20 82 11;
  }
}

I'm currently using Tailwindcss v3.3.5

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.