- Регистрация
- 9 Май 2015
- Сообщения
- 1,483
- Баллы
- 155
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.
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:
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;
}
}
}
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
Blog
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 the data-theme attribute.
Maintain consistent naming: Use a short name like dark for dark mode, and prefix other themes with theme-.
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;
}
}
}
Method 2: Shortcut syntaxNote: This rule only applies to devices that support hover (e.g., desktops or laptops), and not to touch-only devices like phones or tablets.
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
Blog
- Coming soon...
- YouTube: Coming soon...
- DEV.to: Coming soon...
Источник: