Using Checkboxes to Toggle CSS and Create Click Events

More and more lately I’ve seen developers utilizing tricks to create toggle states using pure CSS. This allows you to skip the JavaScript without sacrificing the interaction. How does this work? Is it an acceptable practice?

Today we’re going to examine two distinct methods for utilizing a checkbox to create a click event that swaps between two images using good old HTML and CSS. We’ll finish off with a brief discussion on semantics and the pros/cons of this technique.

The Ultimate Designer Toolkit: 2 Million+ Assets

Envato Elements gives you unlimited access to 2 million+ pro design resources, themes, templates, photos, graphics and more. Everything you'll ever need in your design resource toolkit.

Explore Digital Assets

Like Skinning a Cat

“You essentially create a checkbox in HTML only to hide it and steal its functionality.”

With any CSS trick, there are always a handful of different ways to accomplish the task you’re aiming to achieve. What we’ll be doing here today is learning about how to utilize checkboxes to create two states that can be toggled between using only HTML and CSS. Given that goal, we can easily come up with at least two ways to accomplish it. Even within those two main strategies, you’ll find that there are multiple roads that we could take.

Both methods involve some questionable CSS trickery. You essentially create a checkbox in HTML only to hide it and steal its functionality. The first method simply stretches the checkbox to the full size of the area that you’d like to make clickable and utilizes no label.

The second method makes use of the interesting functionality of labels associated with a checkbox. Even if you hide the checkbox itself, the label can actually be styled, positioned and clicked on to activate the toggle, giving us a completely flexible element to work with that has two possible states.

Let’s dive in and take a closer look at each of these methods.

Method 1

The first way that we’re going to attack this experiment is through making our checkbox eat up the full size of our object and then hiding it. To make this work, all you technically need is a div that contains a checkbox with a class applied. If you want to go further, you can add other attributes such as “name”. We’ll also throw in an image so we’ll have something to toggle.

This should give you a checkbox next to a big image as seen in the following image. Don’t worry about the awkward positioning, we’ll fix that with CSS.



Now that we have some HTML, it’s time to attack this sucker with CSS. It doesn’t take much code but it is a little bit of a weird process so be sure to follow along closely.

The first thing that we want to do here is style the div. We’ll give it a height and a width to match the image that we inserted before so that the photo takes up the entire div. I’ll also give the div a background image that’s different than the other image that we used. This way if we toggle the visibility of the HTML image we’ll see this one underneath. All of this is really just a test anyway so feel free to structure it completely differently. The real focus here is how we use the checkbox to toggle between two states.

The other important part here is setting the position to relative. We’ll use absolute positioning later for the checkbox and it’s important that we set this element to relative to give the checkbox a starting point.

Now it’s time to perform the questionable act of turning our entire image into one big checkbox. To do this, target the “toggle” class that we set up before and set the same height and width that we’ve been using all along.

Next, set the position to absolute and reset the left, top, margin and padding, just to be sure the starting point will be where we want it. This will work in tandem with our previous relative positioning so that our checkbox can now occupy the entire space of the image. To ensure that the checkbox stays on top of everything, set its z-index value to something arbitrarily high.

Finally, set the opacity of the checkbox to 0 to hide it completely. The interesting thing here is that hiding the checkbox doesn’t disable its functionality. So now when you click anywhere on the image, you’ll be toggling the checkbox on and off.

Our hidden checkbox is functioning, but we haven’t set it up to do anything yet. As I mentioned before, we want to toggle the opacity of the HTML image, so we can set up a selector that singles out any inputs with the “toggle” class that are checked, then use the sibling selector to target the image and set its opacity to zero. To make the effect a little nicer, toss in a simple transition.

Try It Out

With that, method one is all finished. Below you should be able to see a link to the CodePen page. Check it out and then come back here for the rest!

Demo: Click here to see it on CodePen.

Method 2

With the first method out of the way, it’s time to explore method #2, which involves the use of a checkbox label. This is added directly before the input. Notice that the “for” value matches the ID for the checkbox. We’ll also toss both images into our HTML this go around just to switch things up.


Once again, we’ll start by adding some basic styles to the div. There’s nothing really special here, just some dimensions and positioning.

Now for something new. Remember that this method involves utilizing the checkbox label instead of the checkbox itself. To do this, set the display to block and give it some dimensions. We included the text “Click Me” in the HTML above so we’ll need to style that as well. Essentially, we’re just transforming the label to give it the look of a button.

On hover, I changed up the colors and added the pointer cursor to further the idea that it’s a clickable element.

Now it’s time to hide the checkbox again, but we’re going to go about it a little differently this go around just to show you that we can. By assigning absolute positioning and some crazy positioning values, we shoot the actual checkbox out of view. Remember, this works because we can still click the label element to pull off the toggle.

To finish this version up, we need three more style blocks. The first positions the second image directly under the first image. From here, we’re using the same code that we did last time to change the opacity on toggle and add in a nice transition.

Try It Out

We’ve finished the second method now, try it out below by clicking the link.

Demo: Click here to see it on CodePen.

Isn’t This JavaScript’s Job?

Without a doubt, this is some fun stuff. With only a wee bit of CSS and HTML, we were able to create a nice little click event. The benefits here are clear: brief code, no JavaScript, ease of implementation, etc.

Unfortunately, both of the methods that we went over above are quite taboo in some circles. This is because they’re both really a bastardization of the checkbox element. We’re not really using the element “semantically,” meaning how it was truly meant to be used, instead we’re just stealing its functionality and wrapping it around other objects.

So how bad is this offense? It depends on who you talk to. An old school coder will tell you that this is bad news. Use JavaScript dummy, that’s what it’s for! Despite this, many of the more impressive CSS tutorials published online recently utilize tricks similar to this (one variation uses radio buttons instead), though they do so without really explaining it in depth. Some of these are so awesome, you simply can’t resist throwing semantics to the wind and blowing past what you previously though possible with only CSS.

With this article I sought to explain how this technique is working on a basic level and point out that it’s, at the very least, considered controversial.

Should I Use This More Often?

I write CSS tutorials for a living. Every single day I try to think of great things that I can teach you. Methods like these present an interesting dilemma. They open up such great possibilities for making amazing pure CSS demos. However, some might consider it a waste of time given the questionable semantic application.

Here I throw it back to you, the Design Shack readers. What do you think? Should I show you cool stuff, even if it makes some semantic sacrifices? Do you want to see some more cool demos built with the two methods outlined in this article? How could you improve this trick? I’d love to hear your thoughts!