🎨 CSS Theme Change
- A tiny JS script to handle CSS themes
- Change CSS theme using
button
, toggle
or a <select>
- It saves chosen theme in browser and uses it again when page reloads
🖥 Demo
💿 Use
JS
Use CDN:
<script src="https://cdn.jsdelivr.net/npm/theme-change@2.0.2/index.js"></script>
Or use NPM:
Install: npm i theme-change --save
and use it in your js file:
import { themeChange } from 'theme-change'
themeChange()
or if it's a React project:
Install: npm i theme-change --save
and use it in your js file:
import { useEffect } from 'react'
import { themeChange } from 'theme-change'
useEffect(() => {
themeChange(false)
}, [])
or if it's a Vue 3 project (using composition API):
Install: npm i theme-change --save
and use it in your js file:
import { onMounted } from 'vue'
import { themeChange } from 'theme-change'
export default {
setup() {
onMounted(() => {
themeChange(false)
})
},
}
or if it's a Vue 2 project (using options API):
Install: npm i theme-change --save
and use it in your js file:
import { themeChange } from 'theme-change'
export default {
mounted: function () {
themeChange(false)
},
}
or if it's a Svelte project:
Install: npm i theme-change --save
and use it in your svelte component that uses one theme-change attributes:
import { onMount } from 'svelte'
import { themeChange } from 'theme-change'
onMount(() => {
themeChange(false)
})
or if it's a SolidJS project:
Install: npm i theme-change --save
and use it in your js/jsx/tsx file:
import { onMount } from 'solid-js'
import { themeChange } from 'theme-change'
onMount(async () => {
themeChange();
})
or if it's a Astro project:
Install: npm i theme-change --save
and use it in your .astro file(s):
Astro is a bit tricky because of how is rendering html page as a MPA (Multiple Pages Application)
Astro projects are therefore subject to FART problem. To prevent this we will use the is:inline astro directive.
If you want to apply themes on a single astro page (remember Astro is an MPA framework) :
src/pages/mypage.astro
---
---
<html lang="en">
<head>
<script is:inline>
if (localStorage.getItem("theme") === null) {
document.documentElement.setAttribute("data-theme", "light");
} else
document.documentElement.setAttribute("data-theme",localStorage.getItem("theme"));
</script>
<script>
import { themeChange } from "theme-change";
themeChange();
</script>
<title>My crazy credit page</title>
</head>
<body>
<h1>Welcome to my credit page!</h1>
</body>
</html>
If you want to apply themes to all your astro pages, you need to execute both scripts in a Astro layout, it would need to wrap all your astro pages like so:
src/layouts/MyCrazyLayout.astro
---
---
<html lang="en">
<head>
<script is:inline>
if (localStorage.getItem("theme") === null) {
document.documentElement.setAttribute("data-theme", "light");
} else
document.documentElement.setAttribute(
"data-theme",
localStorage.getItem("theme")
);
</script>
<script>
import { themeChange } from 'theme-change';
themeChange();
</script>
<meta charset="utf-8" />
<title>My Cool Astro Layout Wraping All My Pages</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<nav>
<a href="#">Home</a>
<a href="#">Posts</a>
<a href="#">Contact</a>
</nav>
<article>
<slot />
</article>
</body>
</html>
src/pages/index.astro
---
import MyCrazyLayout from '../layouts/MyCrazyLayout.astro';
---
<MySiteLayout>
<p>My page content, wrapped in a layout!</p>
</MySiteLayout>
CSS
Set your themeable style as custom properties in CSS like this:
:root {
--my-color: #fff;
}
[data-theme='dark'] {
--my-color: #000;
}
[data-theme='pink'] {
--my-color: #ffabc8;
}
then use your variables on any element
body {
background-color: var(--my-color);
}
HTML
There are 3 options:
-
Using buttons to set a theme
Clicking on these buttons, sets the chosen theme and also adds the ACTIVECLASS
to the chosen button
<button data-set-theme="" data-act-class="ACTIVECLASS"></button>
<button data-set-theme="dark" data-act-class="ACTIVECLASS"></button>
<button data-set-theme="pink" data-act-class="ACTIVECLASS"></button>
-
Toggle between two themes
Clicking on this element, toggles between dark
and light
theme and also adds the ACTIVECLASS
to the element
<button data-toggle-theme="dark,light" data-act-class="ACTIVECLASS"></button>
-
<select data-choose-theme>
<option value="">Default</option>
<option value="dark">Dark</option>
<option value="pink">Pink</option>
</select>
Advance use
Set theme based on OS color-scheme
@media (prefers-color-scheme: dark){
:root{
--my-color: #252b30;
}
}
Use with PurgeCSS
If you're using Purge CSS, you might need to safe list your CSS using the comments below because your secondary themes will be purged
-
Safelist [data-theme]
on postcss config
module.exports = {
purge: {
options: {
safelist: [/data-theme$/],
},
},
}
-
Safelist inside CSS file
[data-theme='dark'] {
--my-color: #252b30;
}
Using custom localStorage key
If you want to use a custom localStorage key, you can add it to the data-key
attribute like this:
<select data-choose-theme data-key="admin-panel">
<button data-key="front-page" data-set-theme="">
<span data-key="premium-user-theme" data-toggle-theme="dark">