CSS3 Custom Checkboxes

Published on
10,701 Points
3 Endorsements
Last Modified:

CSS3 Custom checkboxes

This article shows how to style the checkbox form element using only CSS.

Works in: Chrome, FF, Safari, Opera, IE9+
Uses modernizr.js to check for :checked pseudo class, falling back to plain old checkboxes (IE8 and below)

The basic premise is that we will hide the checkbox and style the label - taking advantage of the fact that clicking on the label toggles the checkbox's checked state.

Based on the above principle we can check whether the checkbox is checked and style the label accordingly. To check the state of the checkbox we'll use the :checked pseudo class.

For this tutorial, we'll make a group of checkboxes that allow the user to select days of the week. It will look like this:

checkbox-group in supported browsers
and in unsupported browsers:
checkbox group fallback
Let's start by creating the HTML template:

<!doctype html>
<meta charset="UTF-8"/>
<title>CSS3 Custom Checkboxes</title>
<div class="checkbox-group">
                	<input type="checkbox" id="mon"/>
	                <label for="mon">MON</label>
                	<input type="checkbox" id="tue"/>
	                <label for="tue">TUE</label>
                	<input type="checkbox" id="wed"/>
	                <label for="wed">WED</label>
                	<input type="checkbox" id="thur"/>
	                <label for="thur">THUR</label>
                	<input type="checkbox" id="fri"/>
	                <label for="fri">FRI</label>
                	<input type="checkbox" id="sat"/>
	                <label for="sat">SAT</label>
                	<input type="checkbox" id="sun"/>
	                <label for="sun">SUN</label>

Open in new window

Each week day is an input type="checkbox" with corresponding label. The id of the input must match the 'for' attribute of its label.

We give the container a class of 'checkbox-group'. We will use this class to qualify the rest of the css rules. This is so we can isolate our custom checkboxes as they pertain to the group. Because at a later date we might want a different style applied to single check boxes, etc..

The first thing is just making sure the list is displayed horizontally:

Copy the following css rules between the <style> tags in the head of your document:

.checkbox-group {
  margin: 20px 0; /* optionally give the whole group some top and bottom margin */
.checkbox-group ul {
  display: inline-block;
  *display: inline; /* old IE does not support inline-block */
  margin-bottom: 0;
  margin-left: 0;
  -webkit-border-radius: 4px;
     -moz-border-radius: 4px;
          border-radius: 4px;
  *zoom: 1; /* give old IE hasLayout*/
 -webkit-padding-start: 0; /* reset default webkit left padding of 40px */

.checkbox-group ul > li {
  display: inline; /* display list items horizontally */

Open in new window

Next we'll hide the input element:
(for now don't worry about the 'csschecked' class. This has to do with making sure there is a fallback for browsers that do not support the :checked pseudo class, and will be explained later)

.checkbox-group input{
	float:left; /* making sure the checkboxes line up correctly in all browsers */
.csschecked .checkbox-group input{
	display:none; /* hide the checkboxes in supported browsers */

Open in new window

Now it's time to style the labels. Here the sky's the limit. You can make them look however you like. This code will mimick the above screenshot:

.csschecked .checkbox-group ul > li > label {
	float: left;
	padding: 5px 12px 2px 12px;
	line-height: 20px;
	text-decoration: none;
	background-color: transparent;
	color: #444;
	border: 1px solid #ccc;
	border-left-width: 0;
.csschecked .checkbox-group ul > li:first-child > label {

  border-left-width: 1px;
  -webkit-border-bottom-left-radius: 4px;
          border-bottom-left-radius: 4px;
  -webkit-border-top-left-radius: 4px;
          border-top-left-radius: 4px;
  -moz-border-radius-bottomleft: 4px;
  -moz-border-radius-topleft: 4px;

.csschecked .checkbox-group ul > li:last-child > label {
  -webkit-border-top-right-radius: 4px;
          border-top-right-radius: 4px;
  -webkit-border-bottom-right-radius: 4px;
          border-bottom-right-radius: 4px;
  -moz-border-radius-topright: 4px;
  -moz-border-radius-bottomright: 4px;

Open in new window

And here's where the magic happens:
When the checkbox is checked, the label gets a different style, making it appear 'selected':

.csschecked .checkbox-group ul > li > :checked + label{
	background-color: #39C;
	color: white;
	background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(255, 255, 255, 0)), to(rgba(0, 0, 0, 0.2)));
	background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.2) 100%);
	background-image: -moz-linear-gradient(top, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.2) 100%);
	background-image: -ms-linear-gradient(top, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.2) 100%);
	background-image: -o-linear-gradient(top, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.2) 100%);
	background-image: linear-gradient(top, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.2) 100%);

Open in new window

Now we want to add :hover and :focus states:

.csschecked .checkbox-group ul > li > :checked + :hover, 
.csschecked .checkbox-group ul > li > :checked + label:focus{
	background-color: #39c;
	background-image: none;

.csschecked .checkbox-group ul > li > label:hover, 
.csschecked .checkbox-group ul > li > label:focus{
	background-color: #ccc;
	background-image: none;
	cursor: pointer;

Open in new window

And that's it!

Well, actually it's not.

If you want to support older browsers gracefully, you'll need a little help from modernizr. We'll use modernizr to detect whether the :checked pseudo class is supported and use the 'csschecked' class to target supported browsers.

If you don't care about backwards support, all you need to do at this point is remove the 'csschecked' from the above CSS.

Add the following into the head of your document above the style element:
Since modernizr doesn't have a check for :checked by default, we've extended it in our own script. (The next version of modernizr which is not out yet has this functionality already in it, so in the future you won't need the extra script)

<script src="http://modernizr.com/downloads/modernizr-latest.js"></script>
Modernizr.addTest('csschecked', function () {
		  return Modernizr.testStyles("#modernizr input {margin-left:0px;} #modernizr input:checked {margin-left: 20px;}", function (elem) {
		    var chx = document.createElement('input');
		    chx.type = "checkbox";
		    chx.checked = "checked";
		    return elem.lastChild.offsetLeft >= 20;

Open in new window

That's it - for real this time!


The file in its entirety is attached.
You can also preview it here:
  • 2
LVL 25

Author Comment

by:Kyle Hamilton
Thank you ;)

Styling form elements has historically been a developer's nightmare. However, with CSS3 and the latest browsers, it's becoming a lot easier.


Expert Comment

by:Brian Matis
Very slick. Saving this article so I can give it a try sometime. Thanks!
LVL 25

Author Comment

by:Kyle Hamilton
thanks Brian :)

Featured Post

Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

Join & Write a Comment

Suggested Articles

Title Views Activity
A jQuery Progress Bar 6,697
From SASS to CSS 1,567
CSS Best Practices 964
Beginner's Guide to HTML and CSS 1,143
In this tutorial viewers will learn how add a full-size background image to a webpage using CSS3. Create a new HTML document with an internal stylesheet.: In CSS, define the html element to have a background image. Use a high resolution image.: In t…
In this tutorial viewers will learn how to style rounded corners for elements in CSS using the border-radius property Begin with a normal styled element such as a div: To style all four corners of the div to be the same degree of roundness, use the …
Next Article:

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month