javascripthtmlcssdomdom-manipulation

Making a switch theme button using localStorage of javascript and CSS variables but facing many issues


I cant believe that i was unable to implement this using all the resources that I know about and I'm stuck on implementing this small feature since last 5-6 hours but it is what it is. I need help to store a single variable on user's localStorage that initially has value 1. If user clicks on a button, then the localStorage value updates to 0. If he clicks again, it again becomes 1. This value is used to switch between light mode and dark mode of the website. Initially I have set the css variable as 1 (for dark mode) and I want to update it using only plain javascript (no libraries) whenever user clicks on the button. The code for the button is in the 2nd try's code. Or it can also be found at my last stackoverflow post regarding the same project.

Here are a few codes of me trying to implement it:

Code implemented and working perfectly without localstorage and with initial variable value as 0:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        :root {
            --numvar: 0;
        }

        html {
            filter: invert(var(--numvar));
        }


        body {
            background: #fff;
        }

        .outer-button {
            display: inline-block;
            height: 28px;
            width: 28px;
            position: relative;
            margin: 0 3px;
        }

        .inner-button {
            display: inline-block;
            position: absolute;
            width: 100%;
            height: 100%;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), inset 0px 0px 1px 2px white;
            border-radius: 20px;
            background: #f5f5f5;
        }

        span {
            display: inline-block;
            vertical-align: middle;
        }

        .status-text {
            color: white;
            text-transform: uppercase;
            font-size: 11px;
            font-family: Futura, sans-serif;
            transition: all 0.2s ease;
        }

        .sliding-switch {
            height: 28px;
            width: 72px;
            position: relative;
        }

        .outer-switch-box {
            overflow: hidden;

            height: 100%;
            width: 100%;
            display: inline-block;
            border-radius: 20px;
            position: relative;
            box-shadow: inset 0 1px 3px 0px #818181, 0px 1px 2px 1px white;
            transition: all 0.3s ease;
            transition-delay: 65ms;
            position: absolute;
            z-index: 1;
        }

        .inner-switch-box {
            position: relative;
            width: 175px;
            transition: all 0.3s ease;
        }

        /* .switch-checkbox:checked+.outer-switch-box .unchecked-text {
            color: transparent;
        }

        .switch-checkbox:not(:checked)+.outer-switch-box .checked-text {
            color: transparent;
        } */

        .switch-checkbox:checked+.outer-switch-box .inner-switch-box {
            left: 20px;
        }

        .switch-checkbox:not(:checked)+.outer-switch-box .inner-switch-box {
            left: -27px;
        }

        .switch-checkbox:checked+.outer-switch-box {
            /* background-image: linear-gradient(#b6d284, #b6d284); */
            background: #492d7b;
            /* background: #b6d284; */
        }

        .switch-checkbox:not(:checked)+.outer-switch-box {
            /* background-image: linear-gradient(#cbcbcb, #dbdbdb); */
            background: #dbdbdb;
        }

        [type="checkbox"] {
            margin: 0;
            padding: 0;
            appearance: none;
            width: 100%;
            height: 100%;
            border: 1px solid black;
            position: absolute;
            top: 0;
            left: 0;
            z-index: 100;
            opacity: 0;
        }

        .unchecked-text{
            color: black !important;
            font-weight: 700;
        }

        .btn-heading{
            color: black;
            font-family: 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Open Sans', 'Helvetica Neue', 'sans-serif';
            padding: .4vw 0;
        }
        body{
            float: left;
        }
    </style>
</head>

<body>
    
    <div class="btn-heading">Change Mode</div>
    <div class="sliding-switch">
        <input type="checkbox" id="btn" class="switch-checkbox" />
        <div class="outer-switch-box">
            <div class="inner-switch-box">
                <span class="status-text checked-text">on</span>
                <span class="outer-button">
                    <span class="inner-button"></span>
                </span>
                <span class="status-text unchecked-text" >off</span>
            </div>
        </div>
    </div>
    <script>
        document.getElementById("btn").addEventListener("click", myfunc);

        function myfunc() {
            let root = document.documentElement;
            let elem = getComputedStyle(root).getPropertyValue("--numvar");

            
            console.log(elem);
            if (elem == 0 ) {
                elem = 1;
            }
            else if (elem == 1 ) {
                elem = 0;
            }
            // alert(elem);
            console.log(elem);
            root.style.setProperty("--numvar", elem);
        }
        
    </script>
</body>

</html>

Before this:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        :root {
            --numvar: 0;
        }

        html {
            filter: invert(var(--numvar));
        }


        body {
            background: #fff;
        }

        .outer-button {
            display: inline-block;
            height: 28px;
            width: 28px;
            position: relative;
            margin: 0 3px;
        }

        .inner-button {
            display: inline-block;
            position: absolute;
            width: 100%;
            height: 100%;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), inset 0px 0px 1px 2px white;
            border-radius: 20px;
            background: #f5f5f5;
        }

        span {
            display: inline-block;
            vertical-align: middle;
        }

        .status-text {
            color: white;
            text-transform: uppercase;
            font-size: 11px;
            font-family: Futura, sans-serif;
            transition: all 0.2s ease;
        }

        .sliding-switch {
            height: 28px;
            width: 72px;
            position: relative;
        }

        .outer-switch-box {
            overflow: hidden;

            height: 100%;
            width: 100%;
            display: inline-block;
            border-radius: 20px;
            position: relative;
            box-shadow: inset 0 1px 3px 0px #818181, 0px 1px 2px 1px white;
            transition: all 0.3s ease;
            transition-delay: 65ms;
            position: absolute;
            z-index: 1;
        }

        .inner-switch-box {
            position: relative;
            width: 175px;
            transition: all 0.3s ease;
        }

        /* .switch-checkbox:checked+.outer-switch-box .unchecked-text {
            color: transparent;
        }

        .switch-checkbox:not(:checked)+.outer-switch-box .checked-text {
            color: transparent;
        } */

        .switch-checkbox:checked+.outer-switch-box .inner-switch-box {
            left: 20px;
        }

        .switch-checkbox:not(:checked)+.outer-switch-box .inner-switch-box {
            left: -27px;
        }

        .switch-checkbox:checked+.outer-switch-box {
            /* background-image: linear-gradient(#b6d284, #b6d284); */
            background: #492d7b;
            /* background: #b6d284; */
        }

        .switch-checkbox:not(:checked)+.outer-switch-box {
            /* background-image: linear-gradient(#cbcbcb, #dbdbdb); */
            background: #dbdbdb;
        }

        [type="checkbox"] {
            margin: 0;
            padding: 0;
            appearance: none;
            width: 100%;
            height: 100%;
            border: 1px solid black;
            position: absolute;
            top: 0;
            left: 0;
            z-index: 100;
            opacity: 0;
        }

        .unchecked-text{
            color: black !important;
            font-weight: 700;
        }

        .btn-heading{
            color: black;
            font-family: 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Open Sans', 'Helvetica Neue', 'sans-serif';
            padding: .4vw 0;
        }
        body{
            float: left;
        }
    </style>
</head>

<body>
    
    <div class="btn-heading">Change Mode</div>
    <div class="sliding-switch">
        <input type="checkbox" id="btn" class="switch-checkbox" />
        <div class="outer-switch-box">
            <div class="inner-switch-box">
                <span class="status-text checked-text">on</span>
                <span class="outer-button">
                    <span class="inner-button"></span>
                </span>
                <span class="status-text unchecked-text" >off</span>
            </div>
        </div>
    </div>
    <script>
        document.getElementById("btn").addEventListener("click", myfunc);
        let avar = true; //assume it exists
        if (localStorage.hardtoimplement) {
            avar = true;
        }
        else {
            localStorage.setItem("hardtoimplement", "on")
        }
        console.log(localStorage.getItem("hardtoimplement"));
        var num = 1;
        function myfunc() {
            let root = document.documentElement;
            let elem = getComputedStyle(root).getPropertyValue("--numvar");

            
            if (typeof (Storage) !== "undefined") {
                // console.log(num);
                if (localStorage.getItem("hardtoimplement") == "on") {
                    num = 1;
                }
                else if (localStorage.getItem("hardtoimplement") == "off") {
                    num = 0;
                }
                console.log(num);
            }
            else {
                alert("Sorry, your browser does not support web storage");
            }
            // console.log(num);
            console.log(localStorage.getItem("hardtoimplement"));

            if (localStorage.getItem("hardtoimplement") == "on") {
                localStorage.hardtoimplement = "off";
            }
            else if (localStorage.getItem("hardtoimplement") == "off") {
                localStorage.hardtoimplement = "on";
            }

            console.log(elem);
            if (num == 0 ) {
                num = 1;
            }
            else if (num == 1 ) {
                num = 0;
            }
            // alert(num);
            console.log(num);
            root.style.setProperty("--numvar", num);
        }
        
    </script>
</body>

</html>

The first try:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>

        let avar = true; //assume it exists
        if (localStorage.thisisvar) {
            avar = true;
        }
        else {
            localStorage.setItem("thisisvar", "on")
        }
        console.log(localStorage.getItem("thisisvar"));
        var num = 0;
        function myfunc() {
            if (typeof (Storage) !== "undefined") {
                // console.log(num);
                if (localStorage.getItem("thisisvar") == "on") {
                    num = 1;
                }
                else if (localStorage.getItem("thisisvar") == "off") {
                    num = 0;
                }
                console.log(num);
            }
            else {
                alert("Sorry, your browser does not support web storage");
            }
            // console.log(num);
            console.log(localStorage.getItem("thisisvar"));

            if (localStorage.getItem("thisisvar") == "on") {
                localStorage.thisisvar = "off";
            }
            else if (localStorage.getItem("thisisvar") == "off") {
                localStorage.thisisvar = "on";
            }
        }
        function func2(){
            alert(num);  //initial value is 0 here
        }
    </script>
</head>

<body>
    <button id="result" onclick=" myfunc()">hi</button>
    <button onclick="func2()">b2</button>

</body>

</html>

I tried looking for this feature at many places like google, codepen, stackoverflow, etc. and I did find many implementations of this feature but I am unable to integrate any of them to my project on my own.

The requirement can be basically defined as:
A CSS variable is initially set to 1 and it should change on button click to 0.
And if user refreshes the page, it should still be 0. 

Thanks.

EDIT:

Integation of answer with project:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
    :root {
            --numvar: 0;
        }

        html {
            filter: invert(var(--numvar));
        }


        body {
            background: #fff;
        }

        .outer-button {
            display: inline-block;
            height: 28px;
            width: 28px;
            position: relative;
            margin: 0 3px;
        }

        .inner-button {
            display: inline-block;
            position: absolute;
            width: 100%;
            height: 100%;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), inset 0px 0px 1px 2px white;
            border-radius: 20px;
            background: #f5f5f5;
        }

        span {
            display: inline-block;
            vertical-align: middle;
        }

        .status-text {
            color: white;
            text-transform: uppercase;
            font-size: 11px;
            font-family: Futura, sans-serif;
            transition: all 0.2s ease;
        }

        .sliding-switch {
            height: 28px;
            width: 72px;
            position: relative;
        }

        .outer-switch-box {
            overflow: hidden;

            height: 100%;
            width: 100%;
            display: inline-block;
            border-radius: 20px;
            position: relative;
            box-shadow: inset 0 1px 3px 0px #818181, 0px 1px 2px 1px white;
            transition: all 0.3s ease;
            transition-delay: 65ms;
            position: absolute;
            z-index: 1;
        }

        .inner-switch-box {
            position: relative;
            width: 175px;
            transition: all 0.3s ease;
        }

        /* .switch-checkbox:checked+.outer-switch-box .unchecked-text {
            color: transparent;
        }

        .switch-checkbox:not(:checked)+.outer-switch-box .checked-text {
            color: transparent;
        } */

        .switch-checkbox:checked+.outer-switch-box .inner-switch-box {
            left: 20px;
        }

        .switch-checkbox:not(:checked)+.outer-switch-box .inner-switch-box {
            left: -27px;
        }

        .switch-checkbox:checked+.outer-switch-box {
            /* background-image: linear-gradient(#b6d284, #b6d284); */
            background: #492d7b;
            /* background: #b6d284; */
        }

        .switch-checkbox:not(:checked)+.outer-switch-box {
            /* background-image: linear-gradient(#cbcbcb, #dbdbdb); */
            background: #dbdbdb;
        }

        [type="checkbox"] {
            margin: 0;
            padding: 0;
            appearance: none;
            width: 100%;
            height: 100%;
            border: 1px solid black;
            position: absolute;
            top: 0;
            left: 0;
            z-index: 100;
            opacity: 0;
        }

        .unchecked-text{
            color: black !important;
            font-weight: 700;
        }

        .btn-heading{
            color: black;
            font-family: 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Open Sans', 'Helvetica Neue', 'sans-serif';
            padding: .4vw 0;
        }
        body{
            float: left;
        }

    </style>
</head>

<body>
    <div class="btn-heading">Change Mode</div>
    <div class="sliding-switch">
        <input type="checkbox" id="btn" class="switch-checkbox" onclick="change()" />
        <div class="outer-switch-box">
            <div class="inner-switch-box">
                <span class="status-text checked-text">on</span>
                <span class="outer-button">
                    <span class="inner-button"></span>
                </span>
                <span class="status-text unchecked-text" >off</span>
            </div>
        </div>
    </div>
    <script>
    if (!localStorage.getItem('thisvarisgud4me')) {
        localStorage.setItem("thisvarisgud4me", "1")
    }

    function change() {
        if (localStorage.getItem('thisvarisgud4me') == '1') {
        localStorage.setItem("thisvarisgud4me", '0')
        } else {
        localStorage.setItem("thisvarisgud4me", '1')
        }

        var num = Number(localStorage.getItem('thisvarisgud4me'));
        let root = document.documentElement;
        root.style.setProperty("--numvar", num);
    }
    var num = Number(localStorage.getItem('thisvarisgud4me'));
    let root = document.documentElement;
    root.style.setProperty("--numvar", num);

    </script>
</body>

</html>


Solution

  • Here is the correct version:

    I think you should learn a bit more js as there were a lot of syntax errors.

    Here are some resources:

    1. JavaScript Reference
    2. Learn JS at freecodecamp.org
    3. Learn JS at Codecademy
    <!DOCTYPE html>
    <html lang="en">
    
      <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
          :root {
            --numvar: 0;
          }
    
          html {
            filter: invert(var(--numvar));
          }
    
        </style>
      </head>
    
      <body>
        <button id="res" onclick="change()">hi</button>
        <script>
          if (!localStorage.getItem('thisvarisgood')) {
             localStorage.setItem("thisvarisgood", "1")
          }
    
          function change() {
            if (localStorage.getItem('thisvarisgood') == '1') {
              localStorage.setItem("thisvarisgood", '0')
            } else {
              localStorage.setItem("thisvarisgood", '1')
            }
    
            var num = Number(localStorage.getItem('thisvarisgood'));
            let root = document.documentElement;
            root.style.setProperty("--numvar", num);
          }
          var num = Number(localStorage.getItem('thisvarisgood'));
          let root = document.documentElement;
          root.style.setProperty("--numvar", num);
    
        </script>
      </body>
    
    </html>