Adding LocalStorage to a Dark Mode Toggle - javascript

I am currently working on adding a dark theme toggle to my website and can't seem to figure out the best way to store the data to LocalStorage. All I am using is a button that toggles the class of "dark" on the main document :root. The actual toggle works perfectly fine, I am only struggling with getting that selected option to stay in LocalStorage.
Here is my code with the LocalStorage that I am trying to add (which does save the key of theme to LocalStorage but not the actual class toggle).
document.addEventListener("DOMContentLoaded", function () {
const theme = localStorage.getItem("theme", "dark");
const darkModeToggle = document.getElementById("modeSwitch");
darkModeToggle.addEventListener("click", function () {
document.documentElement.classList.toggle("dark");
if (document.documentElement.classList.contains("dark")) {
localStorage.setItem("theme", "dark");
}
});
});
Here are my CSS variables as well for reference.
:root {
--main-background: #f8fafb;
--app-background: #ffffff;
--app-background-alt: #fcfcfc;
--app-background-hover: #f8fafb;
--dark-background: #141923;
--main-color: #000000;
--secondary-color: #747987;
}
.dark:root {
--main-background: #141923;
--app-background: #171b2c;
--app-background-alt: #1c2031;
--app-background-hover: #1d213d;
--dark-background: #141923;
--main-color: #ffffff;
--secondary-color: #747987;
}
Thank you so much.

Remove second parameter, should be like that:
const theme = localStorage.getItem("theme");
When you get item from LocalStorage need just key

the way you are storing the theme in the localStore is fine, if want to do it in other way, you could store the theme in an object. Here and example:
localStorage.setItem("theme",JSON.stringify({theme: "dark"}));
To be honest, i think that if your application is not too big you can leave it the way is it.

After playing around a bit, I did figure out a way to successfully store the theme into localStorage. What I am doing is checking to see if the toggle was clicked and "dark" was added to the class list. If it was, I store that in localStorage as "theme", "dark" - and if it "dark" was not added to the class list, I store it in localStorage as "theme", "light".
Then, at the top of the function I check to see if the theme contains "dark" - If the theme contains "dark", I add the class "dark" to the :root, and if it does not I remove it.
I am not sure if this is considered the "correct" way, but it does work!
document.addEventListener("DOMContentLoaded", function () {
const theme = localStorage.getItem("theme", "dark");
const darkModeToggle = document.getElementById("modeSwitch");
if (theme === "dark") {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
darkModeToggle.addEventListener("click", function () {
document.documentElement.classList.toggle("dark");
if (document.documentElement.classList.contains("dark")) {
localStorage.setItem("theme", "dark");
} else {
localStorage.setItem("theme", "light");
}
});
});

Related

Is it possible to make a dark/light mode button that changes the inner css colors on all pages?

Currently I am practicing doing a light/dark mode button for a website I am building with HTML and CSS. The website is in dark mode initially as you open it. But how can I make it that when a user clicks the "light-mode" button for all pages to become dark/light mode based on what he has set?
I am currently running this method:
$(document).ready(function() {
$("#light-mode").click(function() {
$("body").toggleClass("light-mode-bgr");
$("h1").toggleClass("light-mode-text");
$(".message-disc p").toggleClass("light-p");
$("p").toggleClass("light-mode-text");
$(".img-rad label p.maybe").toggleClass("light-mode-btn");
$(".buttons button[type='next']").toggleClass("light", "disabled");
$(".buttons button[type='button']").toggleClass("light-ret");
$("input[type=radio]:checked+label>p").toggleClass("light-radio");
$("input[type=text]").toggleClass("light-inp");
$("input[type=tel]").toggleClass("light-inp");
$("input[type=num]").toggleClass("light-inp");
$("input[type=number]").toggleClass("light-inp");
$("textarea").toggleClass("light-inp");
console.log("clicked");
});
});
but obviously this is not changing the inner css, its only changing classes with the toggle I am using, and if I refresh the page on light-mode, that style is gone back to the default dark-mode style.
How can I make it so that it fully changes the inner css so that it applies to all pages in my website? If so is it possible with JQuery?
found a video https://www.youtube.com/watch?v=wodWDIdV9BY and followed the steps, it required me to change a lot of my css into variables:
:root {
--color-purpe: #FFA14A;
--color-purple-hov: #DE8430;
--body-bgr: #2B3549;
--h1-orange: #ffffff;
--black-labels: #ffffff;
--bas-orange: #7D63DE;
--bas-org-hov: #7D63DE;
--bas-red: #C34437;
--bas-red-hov: #b03628;
--disbaled: #a0a0a0;
}
.lightMode {
--color-purpe: #7D63DE;
--color-purple-hov: #7D63DE;
--body-bgr: #ffffff;
--h1-orange: #E18127;
--black-labels: #000000;
--bas-orange: #FFA14A;
--bas-org-hov: #DE8430;
--bas-red: #C34437;
--bas-red-hov: #b03628;
--disbaled: #a0a0a0;
}
and then I used this function to make it work:
let lightMode = localStorage.getItem('lightMode');
const lightModeToggle = document.querySelector('#light-mode');
// check if light mode enabled
// if off turn on
// if on turn off
const enableLightMode = () => {
document.body.classList.add('lightMode');
localStorage.setItem('lightMode', 'enabled');
}
const disableLightMode = () => {
document.body.classList.remove('lightMode');
localStorage.setItem('lightMode', null);
}
if (lightMode === 'enabled') {
enableLightMode();
}
lightModeToggle.addEventListener('click', () => {
lightMode = localStorage.getItem('lightMode');
if (lightMode !== 'enabled') {
enableLightMode();
console.log(lightMode);
} else {
disableLightMode();
}
});
so when I click the toggle, light mode is applied and changes the :root values into the .lightMode class values and gives me the result I wanted.
The function also stores the value in localStorage so when I refresh the page it doesnt go back to the default "dark mode" style.

Need help making CSS file persistent in Javascript

I have an HTML page with two CSS files, one for a light theme and one for a dark theme. When I click the respective button, the theme changes to either light.css or dark.css.
However, if I reload the site, it goes back to the light theme, even though it was set to dark, is there any possible way to make this work the way I intended.
function toggleTheme() {
// Obtains an array of all <link>
// elements.
// Select your element using indexing.
var theme = document.getElementsByTagName("link")[0];
// Change the value of href attribute
// to change the css sheet.
if (theme.getAttribute("href") == "light.css") {
theme.setAttribute("href", "dark.css");
} else {
theme.setAttribute("href", "light.css");
}
You could save theme to localstorage like this:
const theme = document.getElementsByTagName('link')[0];
const lightTheme = 'light.css';
const darkTheme = 'dark.css';
const newTheme = theme.getAttribute('href') === lightTheme ? darkTheme : lightTheme;
theme.setAttribute('href', newTheme);
// set new theme as preferred
localStorage.setItem('theme', newTheme);
And after page creation we could check existence of preferred theme:
const theme = document.getElementsByTagName('link')[0];
const themeValue = localStorage.getItem('theme');
if (themeValue) {
theme.setAttribute('href', themeValue);
}

How to permanently swap a darkmode logo with javascript?

So I have the following code that manages my dark mode (please note I didn't write the original code, I'm just modifying):
if (toggleTheme) {
toggleTheme.click(function () {
darkMode();
});
};
// Theme Switcher
function darkMode() {
const logo = document.getElementById('logo'); // I Added this line
if (html.hasClass('dark-mode')) {
html.removeClass('dark-mode');
localStorage.removeItem("theme");
$(document.documentElement).removeAttr("dark");
logo.src = logo.dataset.logoLight; // I Added this line
} else {
html.addClass('dark-mode');
localStorage.setItem("theme", "dark");
$(document.documentElement).attr("dark", "");
logo.src = logo.dataset.logoDark // I Added this line
}
}
Here's the relative HTML (note, I'm building with Hugo so included is the Go Templating):
{{- $logo := (resources.Get site.Params.logo).Resize "270x webp q100" -}}
{{- $logoDark := (resources.Get "/images/logo-dark.png").Resize "270x webp q100" -}}
<img id="logo" class="logo__image" src="{{- $logo.RelPermalink -}}" data-logo-light="{{- $logo.RelPermalink -}}" data-logo-dark="{{- $logoDark.RelPermalink -}}" alt="{{ .Site.Title }}" height="{{- div $logo.Height 2 -}}" width="{{- div $logo.Width 2 -}}">
I've only added the three lines noted above to the JavaScript.
So that works exactly like I want. When someone toggles the button for dark mode and the logo flips to the darkmode version.
Great.
Except when they click to a new page, the original logo is in place.
Not sure how to store, check for, and retrieve the appropriate logo because I'm not very good with JavaScript (I just kind of hack together what I need).
How would you do this?
There are a couple ways to add the functionality that you're missing, but the most straightforward way given your current implementation is probably to use the theme value from localStorage.
Your code is already using localStorage to store the current theme. The bit you're missing is some JavaScript that checks the theme value in localStorage and then sets the logo path appropriately. You can use that stored value to determine what the theme is when any page loads by putting some JavaScript in the <head> of every page, or by adding it to the JavaScript file where your existing dark mode toggle logic is:
// Define a function that will check localStorage and set the logo path
function checkThemeAndSetLogo() {
const logo = document.getElementById('logo');
const currentTheme = localStorage.getItem("theme"); // get the theme value from localStorage
if (currentTheme === "dark") {
logo.src = logo.dataset.logoDark;
} else {
logo.src = logo.dataset.logoLight;
}
}
// Call the function so that the logo is updated appropriately
checkThemeAndSetLogo();
If you're interested in further reading and additional options for dark mode, I recommend A Complete Guide to Dark Mode on the Web.
i think you can always store a flag var that check if page was toggled to dark-mode, i show you:
// Theme Switcher
function darkMode(){
if (html.hasClass('dark-mode')){
html.removeClass('dark-mode');
localStorage.removeItem("theme");
$(document.documentElement).removeAttr("dark");
localStorage.setItem('dark_mode', 'false');
darkModeLogo();
}else{
html.addClass('dark-mode');
localStorage.setItem("theme", "dark");
$(document.documentElement).attr("dark", "");
localStorage.setItem('dark_mode', 'true');
darkModeLogo();
}
}
//runs everytime the js file is loaded
function darkModeLogo(){
const logo = document.getElementById('logo'); // I Added this line
const DARK_MODE = localStorage.getItem('dark_mode');
if(eval(DARK_MODE)){
logo.src = logo.dataset.logoLight; // I Added this line
}else{
logo.src = logo.dataset.logoDark // I Added this line
}
}
darkModeLogo();

Where should I put the localStorage in this code?

I am trying to make the dark/light mode theme on my site store locally so that it doesnt untoggle every time a new page is opened or the site is refreshed. Where should I put the localStorage.? Or is the whole thing wrong?
const checkbox = document.getElementById('checkbox');
checkbox.addEventListener('change',()=> {
// change theme of website
document.body.classList.toggle('dark');
});
if you're using vanilla javascript i.e on you html you've loaded your script as below
<html>
...
<script src='/to/scripts.js'></script>
</body>
</html>
Then you can add two functions, one which set the them to localStorage and the other which reads it and make it accessible.
on update the update function sets the new value for the theme,
on read the read function reads the stored value even after refresh/reloads
as below
<html>
....
<script>
//for setting
const toggleTheme = () => {
if(localStorage.getItem('theme') === 'dark'){
localStorage.setItem('theme','light')
}else{
localStorage.setItem('theme','dark')
}
}
//for reading
const theme = () => localStorage.getItem('theme') || 'light'
</script>
<script src='/to/scripts.js'></script>
</body>
</html>
Edit (last answer was not solving the problem)
I think you can use DOMContentLoaded event to set the theme from localStorage, when the checkbox changes you set the selected theme on the storage. This way when the page reloads, it will look for the theme and set it, if theme is not set, it will default to light.
Here is a sample:
document.addEventListener("DOMContentLoaded", function(event) {
const theme = localStorage.getItem('theme');
if(theme === undefined) theme = 'light';
document.body.classList.add(theme);
});
const checkbox = document.getElementById('checkbox');
checkbox.addEventListener('change',(e) => {
const theme = e.target.checked ? 'dark' : 'light';
localStorage.setItem(theme);
document.body.classList.add(theme);
});

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?
Thank you #pvg for providing the link. I had to stare at it for a little to understand what was going on, but I finally figured it out.
The magical line I was looking for was this:
document.documentElement.style.setProperty('--your-variable', '#YOURCOLOR');
That did exactly what I wanted it to do, thank you very much!
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
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);
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);
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">
old jquery magic still working too
$('#yourStyleTagId').html(':root {' +
'--your-var: #COLOR;' +
'}');
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.
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%);
}
/*My style*/
:root {
--hl-color-green: green;
}
/*My update*/
* {
--hl-color-green: #0cc120;
}

Categories

Resources