DEV Community

Cover image for Checkboxes can be excellent buttons
Christian Heilmann
Christian Heilmann

Posted on

Checkboxes can be excellent buttons

I like checkboxes - they give me a simple way in a tool to turn modes on and off without using much space. I especially like it that you can style them with CSS without jumping through hoops like you need to with buttons.

I like to use checkboxes as buttons. And here's how.

A checkbox is a binary state. It is checked or not. So instead of reading out the state in an event handler, I tend to read the checked property.

What does this mean?

Take a look at this codepen.

Looks neat and works. Let's take a look at the how.

The first thing I do is to ensure that my code is accessible. That's why every checkbox needs a label to explain to assistive technology like screen readers what it is.

<input type="checkbox" id="doublewide">
<label for="doublewide">Double width</label>
<input type="checkbox" id="doublehigh"> 
<label for="doublehigh">Double height</label>
<div id="box"></div>
Enter fullscreen mode Exit fullscreen mode

This also has the real practical upshot that when I click on the label text (which is normally much bigger than the checkbox) I change the state of the checkbox. This also helps a lot on mobile devices. From a look and feel point of view, it means I don't need the checkboxes any longer, so let's hide them off screen:

/* Hide checkboxes */
[type=checkbox] {
  position: absolute;
  left: -50vw;
}
Enter fullscreen mode Exit fullscreen mode

We style the labels to look "not selected" or greyed out:

label {
  background: #ccc;
  padding: 5px 10px;
  color: #333;
}

Enter fullscreen mode Exit fullscreen mode

And we colour them when the checkbox is checked (let's also add a transition to make it look smoother):

/* Selected */
[type=checkbox]:checked + label {
  background: #369;
  color: #fff;
  transition: 400ms;
}
Enter fullscreen mode Exit fullscreen mode

Quick aside: you can also style them to interact to keyboard users focusing on the checkboxes and to mouse interaction on the label itself:

[type=checkbox]:focus + label {
  background: #9cf;
  color: #000;
}
[type=checkbox] + label:hover {
  background: #9cf;
  color: #000;
}
Enter fullscreen mode Exit fullscreen mode

Now on to the JavaScript interaction. First, we need some references to the checkbox DOM elements (it makes sense to cache that as reading the DOM is expensive).

const dw = document.querySelector('#doublewide');
const dh = document.querySelector('#doublehigh');
Enter fullscreen mode Exit fullscreen mode

We'll define a change function to be called every time one of the checkboxes is clicked. In this one we read out the checked state of the checkboxes and react accordingly. In this case, changing the width of the box.

const change = _ => {
    box.style.width = dw.checked ? '100px' : '50px';
    box.style.height = dh.checked ? '100px' : '50px';
 };
Enter fullscreen mode Exit fullscreen mode

The last thing to do is to add Event Listeners to the checkboxes to call the change function:

dw.addEventListener('click', change);
dh.addEventListener('click', change);
Enter fullscreen mode Exit fullscreen mode

We could even use Event Delegation instead and apply this to all checkboxes. That way we don't need to add a lot of listeners and we can dynamically add and remove checkboxes without having to re-iterate over them.

document.body.addEventListener('click', e => {
  if (e.target.type === 'checkbox') {
    change();
  }
})
Enter fullscreen mode Exit fullscreen mode

Nothing magical here, but I really like the fact that instead of having to store the state myself, all I need to do is read the checked state and leave the interaction to the browser.


Photo by TeroVesalainen

Top comments (3)

Collapse
 
aardrian profile image
Adrian Roselli

I know the scope of this post is not about CSS selectors, but I want to note for readers that they can also use CSS instead of JavaScript to achieve the same outcome.

codepen.io/aardrian/pen/NWNovdQ

#doublewide:checked ~ #box {
  width: 100px;
}
#doublehigh:checked ~ #box {
  height: 100px;
}
Collapse
 
maxart2501 profile image
Massimo Artizzu • Edited

I guess you don't even have to declare the role, as they're effectively checkboxes, even if they look like buttons.

Collapse
 
codepo8 profile image
Christian Heilmann

Correct. This also works for radio buttons, which is even better as when you declare their name the browser/screenreader automatically detects them as a group.