Semantic element to create a toggle and best practice to undo a function

Sample:

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

<head>
    <meta charset="UTF-8">
    <title>Toggle</title>
    <style>
        #first {
            color: blue;
        }
        #second {
            border: 1px solid green;
        }
        #third {
            background: tan;
        }
    </style>
</head>

<body>
    <label for="box">Toggle</label>
    <input type="checkbox" id="box" onchange="toggle();">
    <div id="first">First</div>
    <div id="second">Second</div>
    <div id="third">Third</div>
    <script>
        function toggle() {
            var box = document.getElementById('box');
            var first = document.getElementById('first');
            var second = document.getElementById('second');
            var third = document.getElementById('third');
            if (box.checked) {
                first.style.color = 'red';
                second.style.border = '2px dotted blue';
                third.style.background = 'olive';
            } else {
                first.style.color = 'blue';
                second.style.border = '1px solid green';
                third.style.background = 'tan';
            }
        }
    </script>
</body>

</html>

DEMO

I wonder if an input checkbox is the right element to create a toggle. I also want to know how to undo what I have in the if clause: in else do I have to repeat my stylesheet or is there a shorter neater way to get back to the initial state?

A checkbox, if it is the only one regarding a question, can be an acceptable toggle. Unlike anchors or buttons, checkboxes and radio buttons have a state, which can be nice. I have used plain anchors/buttons for toggling boxes being tall or short-- in that case, the button doesn’t check the state of the box, but merely mindlessly sets the new height (since CSS is idempotent here-- if my height is already 6em, setting it to 6em again won’t break anything).
If it helps the user to see what the current state is, though, a checkbox or radio button (depending on the setup) could be a better choice than Some Other Random Clickable Thingie. You can also have a <select> with two <option>s as well, with an onchange() listener.

To “undo” the Javascript-added styles, you should be able to set those values to empty strings. I’m not 100% certain all browsers/parsers follow this, but I thought if you have a stylesheet stating
#box {
background-color: #00f;
}
and with javascript do
document.getElementById(‘box’).style.backgroundColor=“#f00”;
then undoing it
document.getElementById(‘box’).style.backgroundColor=‘’;
should give you the following HTML

<div id=“box” style="background-color: ’ ’ ";>filler</div>
and so the original CSS styles should then be seen. If there weren’t any styles set in CSS, the default stylesheet is used:

browser x sets <div>s to display: block without you needing to.
document.getElementById(‘box’).style.display=“inline”;

document.getElementById(‘box’).style.display=“”; //div should now be block.

Not that setting things to empty strings solves the problem you want solved-- remove code redundancy.

What a lot of us tend to do is have a class described in our CSS, and merely use Javascript to add/remove the class in the toggle(), making your Javascript much smaller.

It doesn’t hurt to add comments in your javascript stating what the toggled class does, if you’re working with other developers and the class name isn’t descriptive enough.

Seems like the best solution.
Thanks for the detailed explanation! :slight_smile:

And… if the class changes a CSS property that can be transitioned, such as width, you can get a CSS transition with that for basically a free little animation (instead of using Javascript to do it).

Good point! Thanks again!

I wonder if an input checkbox is the right element to create a toggle. I also want to know how to undo what I have in the if clause: in else do I have to repeat my stylesheet or is there a shorter neater way to get back to the initial state?

Using a checkbox for a toggle works well. You can easily see if the toggle is set. One shortcoming is that the onchange event does not fire on ticking the box in IE 8 or less. To overcome this problem I have added a “Go” button which does nothing more than change the focus away from the checkbox when clicked. This variation works back to IE7.

To overcome your aversion to using the same code twice I have created a script that runs on window.onload. This sets up the initial styles and also creates references to various objects so that you only need document.getElementById() once, rather than every time you click the toggle.

Once the box is ticked the toggle function comes into play, setting the styles according to the toggle state (off or on). This method makes use of the ternary Conditional Operator (test)? “true” : “false”; to reduce the amount of code used.

I have also managed to eliminate nearly all of your CSS. :slight_smile:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=windows-1252" />
<title>Create toggle</title>

<style type="text/css">
body { font-family:arial, helvetica, sans-serif; font-weight:bold; font-size:13px; color:#000; text-align:left; margin:3px 0px; }
input { margin-top:10px; }
#wrap  { width:500px; height:500px; margin-left:20px;  }
.divB { margin-top:5px; height:20px; border:1px solid #000; padding:2px; }
.btn { color:#FFF; font-weight:bold; }
</style>
</head>

<body>

<div id="wrap">
  <label for="box">Toggle</label>
  <input type="checkbox" id="box" onchange="toggle();" value="ON"> &nbsp;<input class="btn" type="button" value="Go">
  <div id="first" class="divB">
    First</div>
  <div id="second" class="divB">
    Second</div>
  <div id="third" class="divB">
    Third</div>
</div>
<!-- end wrap -->
<script>
    function toggle() {
        var isCkd = boxObj.checked;
        firstObj.style.color = (isCkd) ? "#F00" : "#00F";
        secondObj.style.border = (isCkd) ? "2px dotted #00F" : "1px solid #0F0";
        thirdObj.style.backgroundColor = (isCkd) ? "#808000" : "#D2B48C";
    }
  //
    var boxObj, firstObj, secondObj, thirdObj; // global
    window.onload = function () {
        boxObj = document.getElementById('box');
        firstObj = document.getElementById('first');
        secondObj = document.getElementById('second');
        thirdObj = document.getElementById('third');
        toggle();
    }
    //
</script>

</body>

</html>

Thanks for the demo although I’d prefer not to use JavaScript to style elements onload! :slight_smile:
I don’t care about older versions of IE. However, to support them all you need is onclick rather than the onchange event.

onchange has bitten me a few times for various reasons on several form elements, but is there a good reason to use it for radios/checks instead of click?

We are of course assuming that the OP is checking the state in the onclick listener, since for example clicking an already-checked radio button should be idempotent. Not doing so when we have an element who has state is not smart. If onchange avoids the need to do that but offers other problems, I probably still would stick to onclick.

I have also managed to eliminate nearly all of your CSS.

In terms of both rendering and CPU, CSS is cheap compared to JS. I pretty much avoid Javascript doing anything CSS can do in production.

But I could see a benefit to avoiding a mixture of CSS and Javascript if one is exploring an idea in Javascript, and Javascript itself.

Here’s what I created with one line of JavaScript: demo.

haha!