Pretty Checkboxes & Radio Buttons

Valid XHTML 1.0 Transitional Valid CSS!

Thanks to Aaron Weyenberg for creating this style and jQuery magic.

First off, this page shows examples of both a valid XHTML version of Aaron Weyenberg's original pretty checkboxes and a modified version I created for radio buttons. Feel free to look through the source code, but here is how the technique is accomplished:

Pretty Checkboxes

Lets start with the check buttons first (skip to the radio buttons). Here is the basic HTML form. If you're familiar with Aaron's original code you'll see some immediate differences. In order to make the form validate, as well as keep the look and feel of the checkboxes in place if the page needs to degrade gracefully, I changed out a few elements:

  1. I replaced the h4 tag and instead opted to use the fieldset's legend
  2. I changed the unordered list containing the checkboxes in separate list items to a simple divisions
  3. Therefore, the list items are now paragraphs (needed the block element for the styles)
  4. Instead of using paragraphs inline with input tags to handle the text, I used spans. However, I suppose labels might be a better semantic choice
  5. I removed the anchor tags, more on this later
<form method="post" action="http://www.example.com">
  <fieldset>
    <legend>Pretty Checkboxes - Boring Version</legend>
      <div class="clearfix">
        <p>
          <input name="jqdemo" value="value1" type="checkbox" />
          <span>Here is the first selection</span>
        </p>
        <p>
          <input name="jqdemo" value="value2" type="checkbox" />
          <span>Here is the second selection</span>
        </p>
        <p>
          <input name="jqdemo" value="value3" type="checkbox" />
          <span>Here is the third selection</span>
        </p>
        <p>
          <input name="jqdemo" value="value4" type="checkbox" />
          <span>Here is the fourth selection</span>
        </p>
      </div>
    <input type="submit" name="submitbutton" title="Send It!" />
  </fieldset>
</form>

Which produces the following form:

Pretty Checkboxes - Boring Version

Here is the first selection

Here is the second selection

Here is the third selection

Here is the fourth selection

Next, we add the image sprites and a modified version of the CSS developed by Aaron Weyenberg found in his original post. Here is the CSS:

Note, if you're paying attention you'll most likely asking yourself how any of this CSS has to do with the HTML above. I'll explain after the code...

fieldset { border: 0; margin-bottom: 20px; }
legend { font-size: 17px; font-weight: bold; }

.checklist {
	list-style: none;
	margin: 0;
	padding: 0;
}
.checklist p {
	float: left;
	margin-right: 10px;
	background: url(checkboxbg.gif) no-repeat 0 0;
	width: 105px;
	height: 150px;
	position: relative;
	font: normal 11px/1.3 "Lucida Grande","Lucida","Arial",Sans-serif;
}
.checklist p.selected { background-position: -105px 0; }
.checklist p.selected .checkbox-select { display: none; }
.checkbox-select {
	display: block;
	float: left;
	position: absolute;
	top: 118px;
	left: 10px;
	width: 85px;
	height: 23px;
	background: url(select.gif) no-repeat 0 0;
	text-indent: -9999px;
}
.checklist p input { display: none; }

a.checkbox-deselect {
	display: none;
	color: white;
	font-weight: bold;
	text-decoration: none;
	position: absolute;
	top: 120px;
	right: 10px;
}
.checklist p.selected a.checkbox-deselect { display: block; }
.checklist p span {
	display: block;
	text-align: center;
	padding: 8px;
}

Now, how does this work with the HTML above? Well, we can't just style the form using CSS and call it a day. The form needs to properly degrade to the basic version shown earlier in case someone is browsing without the benefit of JavaScript (why do these people still exist...). So, in order to accommodate those caught in 1994 I added a line to the original jQuery code from Aaron to add the .checklist class to the division tag used to contain the checkboxes.

This is done by adding a class the JavaScript will look for in your HTML to apply the style class and eventually the functionality. For this example I chose .prettyCheckboxes (I know, it's not terribly original):

... <div class="prettyCheckboxes clearfix"> ...

Then, in the $(document).ready function I called this to add the styles to the form:

$("div.prettyCheckboxes").addClass("checklist");
Pretty Checkboxes - Pretty Version... Almost

Here is the first selection

Here is the second selection

Here is the third selection

Here is the fourth selection

Note, at this point I left the style for the submit button alone, allowing the developer to choose whether to style it dynamically using JavaScript by adding the class name .sendit (again from Aaron's original post) or simply adding that class to the input[type="submit"] tag:

<input class="sendit" type="submit" name="submitbutton" title="Send It!" />

... and the CSS for the button:

.sendit {
	display: block;
	float: left;
	top: 118px;
	left: 10px;
	width: 115px;
	height: 34px;
	border: 0;
	cursor: pointer;
	background: url(sendit.gif) no-repeat 0 0;
	text-indent: -9999px;
	margin: 20px 0;
}

Of course you could always use input[type="image"] instead of the CSS styles, you're choice. So, now we have a pretty styled set of boxes, but no buttons to click on and of course the actual jQuery magic has yet to be added.

Here is where I altered Aaron's approach once again. Instead of having the anchor tags 'select' and 'cancel' in the form, I opted to add these elements to the DOM using jQuery. After adding the .checklist class to the containing division tag I call this line in my JavaScript (ed. I added a line break ¬ so the code would fit in the box below):

$("div.checklist p").append('<a class="checkbox-select" href="#">Select</a> ¬
<a class="checkbox-deselect" href="#">Cancel</a>');

This adds the two anchor tags to the paragraph tags encapsulating the checkboxes. Of course you could go all out and create each element using jQuery instead of simply appending the HTML to the element, YMMV. Finally we can add the original code developed by Aaron:

$(".checklist .checkbox-select").click(
  function(event) {
    event.preventDefault();
    $(this).parent().addClass("selected");
    $(this).parent().find(":checkbox").attr("checked","checked");
  }
);

$(".checklist .checkbox-deselect").click(
  function(event) {
    event.preventDefault();
    $(this).parent().removeClass("selected");
    $(this).parent().find(":checkbox").removeAttr("checked");
  }
);

A quick explanation on what is going on with the jQuery code above:

  1. $(".checklist .checkbox-select").click( // creates an event for the a.checkbox-select element
  2. ...
  3. event.preventDefault(); //stops the original click event from firing
  4. $(this).parent().addClass("selected"); // Adds the .selected class to the paragraph tag
  5. $(this).parent().find(":checkbox").attr("checked","checked"); // checks the checkbox

Of course the second block of code does the opposite for the cancel anchor element. And when it all comes together we get the following:

Pretty Checkboxes - Pretty Version

Here is the first selection

Here is the second selection

Here is the third selection

Here is the fourth selection

And as you can see, but clicking on the validation badges below, it validates as XHTML 1.0!

Valid XHTML 1.0 Transitional Valid CSS!

Pretty Radio Buttons

So, after all of that, what about radio buttons? Glad you asked (actually Zilus asked Aaron the same question and that got me thinking)!

First, lets look at the HTML for the radio buttons... nothing too terribly new:

<form method="post" action="http://example.com">
  <fieldset>
    <legend>Pretty Radio Buttons - Boring Version</legend>
      <div class="clearfix">
        <p>
          <input name="jqdemo" value="value1" type="radio" />
          <span>Here is the first selection</span>
        </p>
        <p>
          <input name="jqdemo" value="value2" type="radio" />
          <span>Here is the second selection</span>
        </p>
        <p>
          <input name="jqdemo" value="value3" type="radio" />
          <span>Here is the third selection</span>
        </p>
        <p>
          <input name="jqdemo" value="value4" type="radio" />
          <span>Here is the fourth selection</span>
        </p>
      </div>
    <input type="submit" name="submitbutton" title="Send It!" />
  </fieldset>
</form>	

Other than the change from type="checkbox" to type="radio" nothing has changed! Simple.

Pretty Radio Buttons - Boring Version

Here is the first selection

Here is the second selection

Here is the third selection

Here is the fourth selection

Now, for the purposes of this page, I've added a new set of CSS selectors, and I'll explain the changes after the code:

fieldset { border: 0; margin-bottom: 20px; }
legend { font-size: 17px; font-weight: bold; }

.radiolist {
	list-style: none;
	margin: 0;
	padding: 0;
}
.radiolist p {
	float: left;
	margin-right: 10px;
	background: url(checkboxbg.gif) no-repeat 0 0;
	width: 105px;
	height: 150px;
	position: relative;
	font: normal 11px/1.3 "Lucida Grande","Lucida","Arial",Sans-serif;
}
.radiolist p.selected { background-position: -105px 0; }

.radiolist p.selected .radio-select { display: none; }

.radio-select {
	display: block;
	float: left;
	position: absolute;
	top: 118px;
	left: 10px;
	width: 85px;
	height: 23px;
	background: url(select.gif) no-repeat 0 0;
	text-indent: -9999px;
}

.radiolist p input { display: none; }

a.radio-deselect {
	display: none;
	color: white;
	font-weight: bold;
	text-decoration: none;
	position: absolute;
	top: 120px;
	right: 10px;
}
.radiolist p.selected a.radio-deselect { display: block; }

.radiolist p span {
	display: block;
	text-align: center;
	padding: 8px;
}

The styles for fieldset and legend are held over from the checkboxes, but I've added the .radiolist, .radio-select and .radio-deselect to the CSS. These styles are the exact same as the following:

To apply these with the checkbox styles just use the multiple selector syntax (.class1, .class2). Just as the checkbox version I used an identifying CSS class to use JavaScript to apply the proper .radiolist styles, but in this case the class is named .prettyRadiobuttons (again, not very original). And then added the proper addClass() function to my $(document).ready() call.

$("div.prettyRadiobuttons").addClass("radiolist");

Just as with the check boxes this gets us half-way there (Note, I skipped the step about the input[type="submit"] element here, just read up on that above):

Pretty Radio Buttons - Pretty Version... Almost

Here is the first selection

Here is the second selection

Here is the third selection

Here is the fourth selection

Next, we need to append our anchor tags (ed. I added a line break ¬ so the code would fit in the box below):

$("div.radiolist p").append('<a class="radio-select" href="#">Select</a> ¬
<a class="radio-deselect" href="#">Cancel</a>');

And finally, add the bit of jQuery to get the radio buttons working (I'll explain after the code):

$(".radiolist .radio-select").click(
  function(event) {
    event.preventDefault();
    var $boxes = $(this).parent().parent().children();
    $boxes.removeClass("selected");
    $(this).parent().addClass("selected");
    $(this).parent().find(":radio").attr("checked","checked");
  }
);

$(".radiolist .radio-deselect").click(
  function(event) {
    event.preventDefault();
    $(this).parent().removeClass("selected");
    $(this).parent().find(":radio").removeAttr("checked");
  }
);

An explanation of the above code, including the differences that makes this effect work like radio buttons:

  1. $(".radiolist .radio-select").click( // creates an event for the a.radio-select element
  2. ...
  3. event.preventDefault(); // prevents original click event from firing
  4. var $boxes = $(this).parent().parent().children(); // find all paragraphs tags
  5. $boxes.removeClass("selected"); // remove all selected classes
  6. $(this).parent().addClass("selected"); // add selected class to this box alone
  7. $(this).parent().find(":radio").attr("checked","checked"); // enable radio button

The radio button-like effect happens in lines 4 & 5 above. Line 4 simply locates and stores all of the paragraph elements encapsulating the radio buttons so we can call line 5, which removes the .selected class resetting all of the boxes in the radio group. Line 7 is simply a modified version of the checkbox code, but instead of looking for the psuedo selector :checkbox, we check for :radio. And again, the second block of code dealing with .radio-deselect is a reverse of the above, however there is no need to reset all boxes.

When you're done, the following pretty radio buttons are revealed!

Pretty Radio Buttons - Pretty Version

Here is the first selection

Here is the second selection

Here is the third selection

Here is the fourth selection

Just as above with the checkboxes, this code also validates:

Valid XHTML 1.0 Transitional Valid CSS!

Fin.

Want to contact me? Click my name below.
Sean Foushee