Keeping toggle position on page refresh

Viewed 1133

Im quite new to HTML/CSS/JS... I have a light/dark mode toggle switch that activates dark mode on my asp.net core site. Everything works fine and i am using localhost to save the dark/light theme on page refresh or load. The problem is my toggle switch keeps reverting back to light mode. Ive tried a few options and i cant seem to figure out what needs to be done to keep the toggle switch in the correct position on page load.

Here is my code

HTML checkbox:

<div class="toggle-container">
                        <input type="checkbox" id="dark-mode-switch" name="theme" /><label for="dark-mode-switch">Toggle</label>
                    </div>

CSS:

.switch {
    align-self: self-end;
    margin: inherit;
    padding: inherit;
    border-radius: 15px;
    display: grid;
    grid-template-columns: 90px auto;
    grid-template-rows: auto auto;
    grid-template-areas: "title switch" "content content";
}

    .switch h1 {
        margin: auto;
        color: var(--color-headings);
        font-size: 16px;
        line-height: inherit;
    }


input[type=checkbox] {
    height: 0;
    width: 0;
    visibility: hidden;
}

label {
    cursor: pointer;
    text-indent: -9999px;
    width: 52px;
    height: 27px;
    background: grey;
    float: right;
    border-radius: 100px;
    position: relative;
}

    label:after {
        content: '';
        position: absolute;
        top: 3px;
        left: 3px;
        width: 20px;
        height: 20px;
        background: #fff;
        border-radius: 90px;
        transition: 0.4s;
    }

input:checked + label{
    background: var(--color-headings);
}

    input:checked + label:after {
        left: calc(100% - 5px);
        transform: translateX(-100%);
    }

label:active:after {
    width: 45px;
}

html.transition,
html.transition *,
html.transition *:before,
html.transition *:after {
    transition: all 750ms !important;
    transition-delay: 0 !important;

JS

let darkMode = localStorage.getItem('data-theme');
const checkbox = document.querySelector('input[name=theme]');

if (darkMode === 'dark') {
    document.documentElement.setAttribute('data-theme', 'dark')
    localStorage.setItem('data-theme', 'dark')
}

checkbox.addEventListener('change', function () {
    if (this.checked) {
        trans()
        document.documentElement.setAttribute('data-theme', 'dark')
        localStorage.setItem('data-theme', 'dark')
        
    } else {
        trans()
        document.documentElement.setAttribute('data-theme', 'light')
        localStorage.setItem('data-theme', 'light')
    }
})

let trans = () => {
    document.documentElement.classList.add('transition');
    window.setTimeout(() => {
        document.documentElement.classList.remove('transition')
    }, 1000)
}
1 Answers

I think the issue is that you are not reassigning the "checked" property of the checkbox. You have code to update the dark mode based on the checkbox value, but not the other way around.

One way to fix this is to modify your if (darkmode === 'dark') code to set the checked property of checkbox instead of directly updating the data-theme and local storage. This should work:

if (darkMode === 'dark') {
    checkbox.checked = true;
}

You should also rearrange your JS a bit to make sure that you don't have undefined references. I would personally arrange it like this:

const checkbox = document.querySelector('input[name=theme]');

let trans = () => {
    ...
}

checkbox.addEventListener('change', function () {
    ...
})


let darkMode = localStorage.getItem('data-theme');
if (darkMode === 'dark') {
    ...
}

At a minimum, the change event listener must be defined before you update the value of checked, otherwise the event will not fire when you load from localstorage.

Additionally, this code needs to be at the end of your HTML or else wrapped in a domready event handler. Otherwise, checkbox could be undefined and your code would not work.


Update: I just saw that you are using ASP.NET so the following does not apply. But I'll leave it here for reference since it could be helpful to others. Its a pretty common gotcha with localstorage.

And finally, localstorage is not saved for files loaded via a file:// URL. If you are placing this in a file and loading it directly into a web browser (without a server), then the localstorage will be reset every time you leave the page.

Related