'How to change CSS :root color variables in JavaScript
Alright, I'm creating a system for my webpage that allows users to change the theme. How I want to accomplish this is by having all the colors as variables, and the colors are set in the :root part of the CSS.
What I want to do is change those colors via JavaScript. I looked up how to do it, but nothing that I attempted actually worked properly. Here's my current code:
CSS:
:root {
--main-color: #317EEB;
--hover-color: #2764BA;
--body-color: #E0E0E0;
--box-color: white;
}
JS:
(Code to set the theme, it's ran on the click of a button) - I didn't bother adding the :root change to the other 2 themes since it doesn't work on the Dark theme
function setTheme(theme) {
if (theme == 'Dark') {
localStorage.setItem('panelTheme', theme);
$('#current-theme').text(theme);
$(':root').css('--main-color', '#000000');
}
if (theme == 'Blue') {
localStorage.setItem('panelTheme', 'Blue');
$('#current-theme').text('Blue');
alert("Blue");
}
if (theme == 'Green') {
localStorage.setItem('panelTheme', 'Green');
$('#current-theme').text('Green');
alert("Green");
}
}
(Code that is ran when the html is loaded)
function loadTheme() {
//Add this to body onload, gets the current theme. If panelTheme is empty, defaults to blue.
if (localStorage.getItem('panelTheme') == '') {
setTheme('Blue');
} else {
setTheme(localStorage.getItem('panelTheme'));
$('#current-theme').text(localStorage.getItem('panelTheme'));
}
}
It shows the alert, but does not actually change anything. Can someone point me in the right direction?
Solution 1:[1]
For those who want to modify the actual style sheet the following works:
var sheet = document.styleSheets[0];
sheet.insertRule(":root{--blue:#4444FF}");
More info at here: https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule
Solution 2:[2]
To use the values of custom properties in JavaScript, it is just like standard properties.
// get variable from inline style
element.style.getPropertyValue("--my-variable");
// get variable from wherever
getComputedStyle(element).getPropertyValue("--my-variable");
// set variable on inline style
element.style.setProperty("--my-variable", 4);
Solution 3:[3]
I came here looking how to toggle the :root color-scheme with JavaScript, which sets the browser to dark mode (including the scroll bars) like this:
:root {
color-scheme: dark;
}
using the @Daedalus answer above, this is how I implemented my dark mode detection from user preference:
const userPrefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
const preferredTheme = userPrefersDarkMode ? 'dark' : 'light';
document.documentElement.style.setProperty("color-scheme", preferredTheme);
or with saved toggle:
const savedTheme = localStorage.getItem('theme');
if (savedTheme == 'dark') {
thisTheme = 'light'
}
else {
thisTheme = 'dark'; // the default when never saved is dark
}
document.documentElement.style.setProperty("color-scheme", thisTheme);
localStorage.setItem('theme', thisTheme);
see also the optional meta tag in the header:
<meta name="color-scheme" content="dark light">
Solution 4:[4]
old jquery magic still working too
$('#yourStyleTagId').html(':root {' +
'--your-var: #COLOR;' +
'}');
Solution 5:[5]
Read only, retrieve all CSS --root rules in an array, without using .getComputedStyle().
This may allow to retrieve values before full DOM content load, to create modules that use global root theme variables, but not via CSS. (canvas context...)
/* Retrieve all --root CSS variables
* rules into an array
* Without using getComputedStyle (read string only)
* On this example only the first style-sheet
* of the document is parsed
*/
console.log(
[...document.styleSheets[0].rules]
.map(a => a.cssText.split(" ")[0] === ":root" ?
a.cssText.split("{")[1].split("}")[0].split("--") : null)
.filter(a => a !== null)[0]
.map(a => "--"+a)
.slice(1)
)
:root {
--gold: hsl(48,100%,50%);
--gold-lighter: hsl(48,22%,30%);
--gold-darker: hsl(45,100%,47%);
--silver: hsl(210,6%,72%);
--silver-lighter: hsl(0,0%,26%);
--silver-darker: hsl(210,3%,61%);
--bronze: hsl(28,38%,67%);
--bronze-lighter: hsl(28,13%,27%);
--bronze-darker: hsl(28,31%,52%);
}
Solution 6:[6]
TL;DR
A solution to the problem could be the below code:
const headTag = document.getElementsByTagName('head')[0];
const styleTag = document.createElement("style");
styleTag.innerHTML = `
:root {
--main-color: #317EEB;
--hover-color: #2764BA;
--body-color: #E0E0E0;
--box-color: white;
}
`;
headTag.appendChild(styleTag);
Explanation:
Although @Daedalus answer with document.documentElement does the job pretty well, a slightly better approach is to add the styling into a <style> HTML tag (solution proposed).
If you add document.documentElement.style then all the CSS variables are added into the html tag and they are not hidden:
On the other hand, with the proposed code:
const headTag = document.getElementsByTagName('head')[0];
const styleTag = document.createElement("style");
styleTag.innerHTML = `
:root {
--main-color: #317EEB;
--hover-color: #2764BA;
--body-color: #E0E0E0;
--box-color: white;
}
`;
headTag.appendChild(styleTag);
the HTML tag will be cleaner and if you inspect the HTML tag you can also see the :root styling as well.
Solution 7:[7]
I think this is cleaner and easier to remember.
to set/get css variables to/from :root
const root = document.querySelector(':root');
// set css variable
root.style.setProperty('--my-color', 'blue');
// to get css variable from :root
const color = getComputedStyle(root).getPropertyValue('--my-color'); // blue
Example: setting multiple variables all at once
const setVariables = vars => Object.entries(vars).forEach(v => root.style.setProperty(v[0], v[1]));
const myVariables = {
'--color-primary-50': '#eff6ff',
'--color-primary-100': '#dbeafe',
'--color-primary-200': '#bfdbfe',
'--color-primary-300': '#93c5fd',
'--color-primary-400': '#60a5fa',
'--color-primary-500': '#3b82f6',
'--color-primary-600': '#2563eb',
'--color-primary-700': '#1d4ed8',
'--color-primary-800': '#1e40af',
'--color-primary-900': '#1e3a8a',
};
setVariables(myVariables);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Manabu |
| Solution 2 | iProDev |
| Solution 3 | gojimmypi |
| Solution 4 | v2p |
| Solution 5 | |
| Solution 6 | |
| Solution 7 | Pakpoom Tiwakornkit |


