This content originally appeared on DEV Community and was authored by vrauuss softwares
Themes define the visual style and layout of a website, making the user experience more enjoyable. In this article, I’ll show you how to create different themes using Tailwind CSS.
Note: I used AI tools to help draft and structure this article because I’m still building my technical writing skills. However, all the code was written, tested, and reviewed by me.
1. Add custom variants with @custom-variant
You can create new themes or conditional styles through custom variants added by the @custom-variant
directive. But first, here are some important points to consider:
Define in
index.css
: Add@custom-variant
declarations to your main CSS file (e.g.,index.css
).Enable dark mode: Create a
dark
variant and activate it using thedata-theme
attribute.Maintain consistent naming: Use a short name like
dark
for dark mode, and prefix other themes withtheme-
.
Method 1: Nesting syntax
This method allows nesting additional rules within the block:
@custom-variant dark {
&:where([data-theme="dark"] *) {
@slot;
}
}
@custom-variant theme-midnight {
&:where([data-theme="midnight"] *) {
@slot;
}
}
Example applying styles only on devices that support hover:
@custom-variant any-hover {
@media (any-hover: hover) {
&:hover {
@slot;
}
}
}
Note: This rule only applies to devices that support hover (e.g., desktops or laptops), and not to touch-only devices like phones or tablets.
Method 2: Shortcut syntax
This syntax is useful when you don’t need to nest other rules:
@custom-variant dark (&:where([data-theme="dark"] *));
@custom-variant theme-midnight (&:where([data-theme="midnight"] *));
2. Apply theme-specific styles in markup
Once data-theme
is set, you can apply conditional styles using your custom variant prefix in your utility classes:
<body class="bg-white theme-dark:bg-black-800 theme-midnight:bg-purple-800">
3. Set themes via data-theme
attribute
To activate a theme, set the data-theme
attribute on the <html>
tag:
<html data-theme="midnight" lang="en">
You can dynamically change the value to switch themes:
<html data-theme="light" lang="en"> <!-- No need to add custom variant -->
<html data-theme="dark" lang="en">
<html data-theme="midnight" lang="en">
4. Bonus: Component to switch between themes dynamically
This example uses a <select>
element and updates the data-theme
attribute on <html>
to control the active theme.
import React, { useState, useEffect } from "react";
import capitalize from "./utils/capitalize"; // Helper to capitalize names
// Available themes
const themes = [
{ name: "light", icon: "☀" },
{ name: "dark", icon: "🌑" },
{ name: "midnight", icon: "🌌" },
];
function App() {
// State for the current theme index
const [idx, setIdx] = useState(0);
const theme = themes[idx];
// Update data-theme when theme changes
useEffect(() => {
document.documentElement.setAttribute("data-theme", theme.name);
}, [theme]);
// Update index state based on the selected theme
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setIdx(themes.findIndex((t) => t.name === e.target.value));
};
return (
<div className="space-y-2 text-center">
<label htmlFor="theme-select" className="block font-medium">
Choose a theme:
</label>
<select
id="theme-select"
value={theme.name}
onChange={handleChange}
className="rounded border px-3 py-1"
>
{themes.map((theme) => (
<option key={theme.name} value={theme.name}>
{theme.icon} {capitalize(theme.name)}
</option>
))}
</select>
</div>
);
}
export default App;
Note: Soon, I’ll create a customizable and more complete <SwitchTheme>
component.
Contact & Links
Contact
- YouTube: @vrauuss-softwares
- GitHub: vrauuss-softwares
Blog
- Coming soon…
Articles
- YouTube: Coming soon…
- DEV.to: Coming soon…
References
- Tailwind CSS: Adding custom variants
- MDN: Customizable select elements
This content originally appeared on DEV Community and was authored by vrauuss softwares