Switching themes
Since the theme is set by the data-theme attribute, switching it means changing that attribute on <html>. You can do it with a couple of lines of JavaScript, or with no JavaScript at all using the theme-controller class.
Switching from JavaScript
A data-* attribute is available in JavaScript through the dataset property. The buttons below write the theme name into document.documentElement.dataset.theme:
<link href="https://cdn.jsdelivr.net/npm/daisyui@5" rel="stylesheet" type="text/css">
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div class="rounded-box bg-base-100 p-4 text-base-content">
<p class="mb-3">LearnUp dashboard</p>
<button class="btn btn-sm" data-set-theme="light">Light</button>
<button class="btn btn-sm" data-set-theme="dark">Dark</button>
</div>
<script>
document.querySelectorAll('[data-set-theme]').forEach((button) => {
button.addEventListener('click', () => {
document.documentElement.dataset.theme = button.dataset.setTheme;
});
});
</script>Click "Dark" — the block turns dark with light text; "Light" brings back the original look. The block is repainted because its bg-base-100 and text-base-content classes take their colors from the current theme.
Remembering the choice
To keep the theme after a reload, save the choice in localStorage and restore it when the page opens. In a Vite project create the file src/theme.js:
// src/theme.js
const saved = localStorage.getItem('theme');
if (saved) {
document.documentElement.dataset.theme = saved;
}
document.querySelectorAll('[data-set-theme]').forEach((button) => {
button.addEventListener('click', () => {
const theme = button.dataset.setTheme;
document.documentElement.dataset.theme = theme;
localStorage.setItem('theme', theme);
});
});Import it in src/main.js with import './theme.js';. Now the chosen theme stays after the page is refreshed.
No JavaScript: theme-controller
daisyUI can switch the theme with pure CSS. Give a checkbox or a toggle the theme-controller class and put the theme name into its value attribute. While it is checked, that theme applies to the page:
<link href="https://cdn.jsdelivr.net/npm/daisyui@5" rel="stylesheet" type="text/css">
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div class="rounded-box bg-base-100 p-4 text-base-content">
<label class="flex cursor-pointer items-center gap-2">
Light
<input type="checkbox" value="dark" class="toggle theme-controller">
Dark
</label>
</div>Click the toggle — the block turns dark. toggle is the switch component, covered in the forms chapter. For several themes, use radio buttons with a shared name, each with its own value.
| Approach | Pros | Cons |
|---|---|---|
JavaScript and data-theme | Can remember the choice | Needs a script |
theme-controller | Not a line of JS | The choice resets on reload |
Common mistake
Restoring the theme only in src/theme.js. Vite loads scripts as modules (type="module"), and modules run after the page has been parsed. So the page shows in the default theme first and only later repaints — the screen visibly "flashes". Move the lines that read localStorage and set data-theme into a small <script> tag right in the <head> of index.html, and keep the button handlers in src/theme.js.