# Theming With Tailwind CSS ## Introduction As accessibility becomes increasingly important, it has become necessary to have at least an extra theme (mostly dark) on a web page. In this article, I will show the ways of creating multiple themes in a Tailwind CSS application as well as create switches to toggle them. **Tailwind CSS** is a popular, utility-first CSS framework that provides pre-designed CSS classes to quickly and easily style your web pages. Additionally, it provides a set of customization options, allowing developers to easily tweak and adjust the styles to their specific needs. ## Pre-requisite To follow this tutorial completely, you should have basic knowledge of the following: - HTML - CSS and [CSS variables](https://blog.openreplay.com/working-with-css-variables/) - Javascript - TailwindCSS As well as have the following installed on your machine: - A Code Editor - Nodejs and npm - Git ## Installation and Overview Follow the steps below to start a Tailwind CSS boilerplate ### Project Starter In your terminal enter the commands ```bash= git clone https://github.com/Complexlity/tailwind-theming.git cd tailwind-theming npm install npm run watch ``` ### Folder Overview On Completion, you should have a similar folder structure ![](https://i.imgur.com/5Wis40S.png) For this tutorial, we would work with four files - index.html - input.css - tailwind.config.js - main.js ## Creating Call To Action Component 1. Update `index.html` with the code below ```htmlembedded= <!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Tailwind Theming</title> <link rel="stylesheet" href="output.css" /> <script src="main.js" defer></script> </head> <body class="bg-gray-400"> <div class="wrapper mt-16 px-8"> <div class="theme-container mx-auto max-w-[50rem] rounded-xl shadow-md bg-white"> <div class="lg:py-16 lg:px-8 z-20 mx-auto w-full py-12 px-4 text-center sm:px-6" > <h2 class="theme-header text-3xl font-extrabold text-black sm:text-4xl"> <span class="block"> Hey There 👋 </span> <span class="block text-indigo-500"> Happy Learning!! </span> </h2> <p class="mx-auto mt-4 max-w-md text-xl text-gray-400"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quaerat necessitatibus eos consequuntur? </p> <div class="lg:mt-0 lg:flex-shrink-0"> <div class="mt-12 inline-flex rounded-md shadow"> <button type="button" class="w-full rounded-lg bg-indigo-600 py-4 px-6 text-center text-base font-semibold text-white shadow-md transition duration-200 ease-in hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-indigo-200" > Get started </button> </div> </div> </div> </div> </div> </body> </html> ``` Open `index.html` in your browser to see the output below. ![](https://i.imgur.com/tkd1f6O.png) ## Theming with Classes ### Creating dark theme using inline class The easiest mode of using dark theme in tailwind is using `dark` class. Update the code in `tailwind.config.js`. ```javascript= // tailwind.config.js module.exports = { content: ["./*.html"], darkMode: "class", theme: { extend: {}, }, plugins: [], }; ``` ```darkMode:class``` enables `dark` state to be used in conjunction with tailwind classes to set different properties between the normal mode and dark mode. Update `index.html` in the following ways: - Add `dark` class to the `body` (Line 13) - Add `dark:bg-gray-800` class to `div.theme-container` (Line 15) - Add `dark:text-white` class to `h2.theme-header` (Line 19) See the code below for an illustration ```htmlembedded= .... <body class="dark ...."> .... <div class="theme-container dark:bg-gray-800 ...."> .... <h2 class="theme-header dark:text-white .... "> .... ``` NOTE: `....` represents unchanged code We added the `dark` to the `body` tag to enable this. Removing it would reset back to normal mode ### Create Toggle Now in the current state, we have to manually add or remove the `dark` class from the body but this is usually now what we want. We would want a switch to toggle between these modes. #### Insert switch button ```htmlembedded= <!-- Replace index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Tailwind Theming</title> <link rel="stylesheet" href="output.css" /> <script src="main.js" defer></script> </head> <body class="bg-gray-400"> <div class="wrapper mt-16 px-8"> <div class="theme-container mx-auto max-w-[50rem] rounded-xl bg-white shadow-md dark:bg-gray-800" > <div class="mx-8 pt-4 text-end"> <!-- Checkbox start --> <div class="relative mr-2 inline-block w-10 select-none align-middle transition duration-200 ease-in" > <input type="checkbox" name="theme-toggle" id="theme-toggle" class="peer absolute block h-6 w-6 cursor-pointer appearance-none rounded-full border-4 bg-white checked:right-0 checked:border-green-400" /> <label for="theme-toggle" class="block h-6 cursor-pointer overflow-hidden rounded-full bg-gray-300 peer-checked:bg-green-400" ></label> </div> <label for="toggle" class="theme-text text-bold text- font- font-bold tracking-wider text-gray-700 dark:text-white" >LIGHT</label > </div> <!-- Checkbox End --> <div class="lg:py-16 lg:px-8 z-20 mx-auto w-full py-12 px-4 text-center sm:px-6" > <h2 class="theme-header text-3xl font-extrabold text-black dark:text-white sm:text-4xl" > <span class="block"> Hey There 👋 </span> <span class="block text-indigo-500"> Happy Learning!! </span> </h2> <p class="mx-auto mt-4 max-w-md text-xl text-gray-400"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quaerat necessitatibus eos consequuntur? </p> <div class="lg:mt-0 lg:flex-shrink-0"> <div class="mt-12 inline-flex rounded-md shadow"> <button type="button" class="w-full rounded-lg bg-indigo-600 py-4 px-6 text-center text-base font-semibold text-white shadow-md transition duration-200 ease-in hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-indigo-200" > Get started </button> </div> </div> </div> </div> </div> </body> </html> ``` The Output ![](https://i.imgur.com/EGLmJfU.png) We added a checkbox which would enable the toggle. #### Implement Theme Toggling We need to make use of some Javascript to make the switch work as expected.<br/> Update `main.js` with the code below. ```javascript= // main.js const body = document.querySelector("body"); const themeToggle = document.querySelector("#theme-toggle"); const themeText = document.querySelector(".theme-text"); let darkTheme = false; themeToggle.addEventListener("click", () => { body.classList.toggle("dark"); darkTheme = !darkTheme; themeText.textContent = darkTheme ? "DARK" : "LIGHT"; }); ``` Here, we get the toggle as well as the body element and create the toggle function to change the state. We also change the toggle text when clicked ![](https://i.imgur.com/dt9NieE.gif) ## Theming with CSS Variables Consider a scenario where you need more than just `light` and `dark` themes. Using the tailwind `dark` class would not be able to handle that. With the help of CSS Variables, you would be able to create a custom design system that handles as many themes as you want. ### Project Starter - Start a new project folder - Open the folder on your terminal and run the following: ```bash= git clone https://github.com/Complexlity/tailwind-theming.git cd tailwind-theming npm install npm run watch ``` Having the same folder structure and files as in the previous project, we create a different component to handle multiple themes. ### Creating Call To Action Component Copy the code below into `index.html` ```htmlembedded= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Tailwind Theming</title> <link rel="stylesheet" href="output.css" /> <script src="main.js" defer></script> </head> <body class="bg-gray-500"> <div> <div class="wrapper mt-16 px-8"> <div class="themed-background bg-gray-200 mx-auto max-w-[50rem] rounded-xl shadow-md" > <div class="px-4 pt-4"> <label for="themes" class="themed-label text-indigo-600 mb-2 block text-center text-sm font-medium " >CHOOSE A THEME</label > <select id="themes" class="block w-full cursor-pointer rounded-lg border p-2.5 text-sm outline-transparent" > <option value="" selected>Default (Light)</option> <option value="blue">Blue</option> <option value="red">Red</option> <option value="purple">Purple</option> </select> </div> <div class="relative mx-auto max-w-4xl overflow-hidden sm:rounded-2xl" > <div class="relative mx-auto max-w-2xl py-16 px-4 text-center sm:py-20 sm:px-6 lg:px-8" > <h2 class="themed-header text-indigo-600 text-3xl font-extrabold sm:text-4xl" > <span class="block">Consistency matters.</span> <span class="block">Practice makes perfect.</span> </h2> <p class="themed-subheader text-gray-800 mt-4 text-lg leading-6"> Ac euismod vel sit maecenas id pellentesque eu sed consectetur. Malesuada adipiscing sagittis vel nulla nec. </p> <div class="mx-auto mt-10 max-w-sm sm:flex sm:max-w-none sm:justify-center" > <a href="#" class="themed-button bg-indigo-600 text-gray-200 flex items-center justify-center rounded-md border border-transparent px-4 py-3 text-base font-medium shadow-sm sm:px-8" > Get started </a> </div> </div> </div> </div> </div> </div> </body> </html> ``` ![](https://i.imgur.com/QTomVFr.png) We have a similar call to action component with a select button which we would use to toggle themes. ### Create CSS Variables for the colors of `themed-*` elements. Replace `input.css` with the code below ```css= /* input.css */ @tailwind base; @tailwind components; @tailwind utilities; @layer base { :root { --color-text-base: #4f46e5; /* bg-indigo-600 */ --color-text-muted: #1f2937; /* bg-gray-800 */ --color-fill: #e5e7eb; /* bg-gray-200 */ --color-text-inverted: #e5e7eb; /* bg-gray-200 */ --color-button-base: #4f46e5; /*bg-indigo-600 */ } } ``` Here, we create variables from the [tailwind colors](https://tailwindcss.com/docs/customizing-colors) using their hex code equivalent. ### Add Custom Color Configuration Update `tailwind.config.js` with the code below ```javascript= module.exports = { content: ["./*.html"], theme: { extend: { textColor: { skin: { base: "var(--color-text-base)", muted: "var(--color-text-muted)", inverted: "var(--color-text-inverted)", }, }, backgroundColor: { skin: { fill: "var(--color-fill)", button: "var(--color-button-base)", }, }, }, }, plugins: [], }; ``` Here, we use the CSS variables to make custom tailwind colors. These colors can be accessed in html elements. For example, `base` color could be accessed by `text-skin-base` and `fill` color can be accessed by `bg-skin-fill` ### Replace hard-coded colors with the created colors Update the following elements in `index.html`: - **div.themed-background** (Line 15 ): Replace `bg-gray-200` with `bg-skin-fill` - **label.themed-label** (Line 20 ): Replace `text-indigo-600` with `text-skin-base` - **h2.themed-header** (Line 40 ): Replace `text-indigo-600` with `text-skin-base` - **p.themed-subheader** (Line 45): Replace `text-gray-800` with `text-skin-muted` - **a.themed-button** (Line 54): Replace `bg-indigo-600` with `bg-skin-button` and `text-gray-200` with `text-skin-inverted` **Note**: Depending on the text editor and code formatting, the line number may vary ```htmlmixed= .... <div class="themed-background bg-skin-fill mx-auto ...."> <!-- bg-gray-200 now bg-skin-fill --> .... <label for="themes" class="themed-label text-skin-base mb-2 ....">CHOOSE A THEME</label> <!-- text-indigo-600 now text-skin-base --> .... <h2 class="themed-header text-skin-base text-3xl .... "> <!-- text-indigo-600 now text-skin-base --> .... <p class="themed-subheader text-skin-muted mt-4 .... "> <!-- text-gray-800 now text-skin-muted --> .... <a href="#" class="themed-button bg-skin-button text-skin-inverted flex ...."> <!-- bg-indigo-600 now bg-skin-button , text-gray-200 now text-skin-inverted --> ``` **Note**: `....` represents unchanged code Now the component should still look the same but without any hardcoded colors on the elements ### Create Multiple Themes Now you could create as many themes as you need using the CSS variables. We would create three more namely: *Blue*, *Red* and *Purple*. Replace `input.css` with the code below ```css= /* input.css */ @tailwind base; @tailwind components; @tailwind utilities; @layer base { :root { --color-text-base: #4f46e5; --color-text-muted: #1f2937; --color-fill: #e5e7eb; --color-text-inverted: #e5e7eb; --color-button-base: #4f46e5; } .blue { --color-text-base: #fff; --color-text-muted: #bfdbfe; --color-fill: #1e40af; --color-text-inverted: #1d4ed8; --color-button-base: #fff; } .red { --color-text-base: #fff; --color-text-muted: #fecaca; --color-fill: #991b1b; --color-text-inverted: #b91c1c; --color-button-base: #fff; } .purple { --color-text-base: #fff; --color-text-muted: #e9d5ff; --color-fill: #6b21a8; --color-text-inverted: #7e22ce; --color-button-base: #fff; } } ``` Now we created more themes. We used scoping of CSS variables to achieve it. These colors would only apply under the specific class while the `:root` one remains the default ### Implement Theme Toggling We already created the select to toggle these themes so now we need to use Javascript to make it work as expected. Insert the code below into `main.js` ```javascript= // Insert code into main.js const themedContainer = document.querySelector("body > div"); const selectOptions = document.querySelector("#themes"); selectOptions.addEventListener("input", (e) => { themedContainer.className = e.target.value; }); ``` In the code above, we change the class of the parent element depending on the value of the option selected. Now the code works the same as the image below. ![](https://i.imgur.com/G7EdBI9.gif) ### Live Link You can see both methods in action [here](https://tailwind-theming.netlify.app/) ## Information For Usage on Frameworks Front-end frameworks have become increasingly popular so it is important to know how to apply these methods on your preferred framework ### Installing TailwindCSS Tailwind is compatible with many front-end frameworks including React, Vue, Angular, Svelte, and the likes ![](https://i.imgur.com/FLv43vY.png) Head over to the [Tailwind documentation](https://tailwindcss.com/docs/installation/framework-guides) and pick your preferred framework ### Applying Theming Idea When Using Frameworks In your prefered framework, theming works the same way as we have seen in this article. #### Using Class 1. Update `tailwind.config.js` by adding `darkmode: "class"` 2. Use the `dark` class on html elements (or Jsx components in some frameworks) 3. Creating and implementing a toggle button #### Using CSS Variables 1. Create CSS variables representing the themed colors 2. Creating custom tailwind colors with the CSS variables (in `tailwind.config.js`) 3. Use these custom color names in HTML elements (or Jsx components in some frameworks) 4. Create a toggle switch to dynamically change the theme class ## Conclusion In this article, we looked at how to create a dark theme as well as creating multiple themes using Tailwind CSS. With the ease of implementation here and for accessibility reasons, you should always create at least a dark theme for your web sites and applications