An Image-Based ‘Checkbox’ Via JavaScript / DOM

Recently asked on Yahoo! Answers:

Use a custom image for check boxes???? Please help, I”m going insane over such a simple thing.?

Heya.

Don’t worry, I’m not really going insane – it’s just kind of frustrating because such a simple little thing is giving me trouble. I want to use custom images for check boxes on a HTML page.

The best way I can describe this is that I want a bright red flashing gif to be there by defualt, then for that to change to a green flashing gif when it’s clicked.

I don’t care if it’s done using a real checkbox, I don’t need it to actually work. I only need the picture to change when it’s clicked, and stay changed after that unless clicked again.

Apparently either it’s such a simple thing to do that no one has ever talked about it, or no one has ever needed to do it before and never given it any thought, because I’ve looked for help with this all afternoon and tried 6 different ideas of my own with no luck. I can write a fully functional & good looking page in notepad but not get a dumb little image to change when it’s clicked. Go figure.

Please help! Thank you 🙂

I’ve written about using JavaScript / Document Object Model (DOM) manipulation to change images onclick, onmouseover or via virtually any other event on many occasions. But it’s the idea of using an image as a checkbox that got me curious: Sure, we can change any image onclick, but can we also get the id attributes of all the checked items for use in form processing?

Yes, we can! So we’ll tackle this question in three parts: Example 1 will simply change images on click; Example 2 will let us find out which images are “checked,” via a JavaScript array; and Example 3 will assign the checked images to regular, old HTML check boxes, so you can process the form as you would via any HTML postback.

As always, I will provide links to working demos at the end of each example.

Example 1: Change Image On Click

The basic request from the questioner only requires us to change an image any time an item is clicked. For that, we can use a variation on the image-swapping functions I have previously discussed.

Step 1: Prepare The HTML

First up, let’s prep each IMG tag for image swapping. Again, we need to add two essential attributes to each IMG tag we want to have take a new source: a unique ID for the image, and an onclick event handler. In this case, we’ll call a function named swapImage, that takes as its argument the ID for this image.

<img id="item1" onclick="swapImage('item1')" src="images/1.jpg" alt="" />

I’m also going to add an onclick event to each “label” for each of the image “checkboxes.” In HTML, if you click on a LABEL element, it will toggle, or give focus to, the element to which it is tied.

In DOM, you can click on any element and it will fire the onclick event. So, if I assign an onclick event handler to text associated with an image, I can make that text behave as though it were a LABEL for the image-based “checkbox.” Neat, eh?

In this example, I’ve cheated on layout by putting everything in a table, so the TD elements containing my “labels” will take the onclick event:

<td onclick="swapImage('item1')">This is item 1. If you click on the icon to the left, or this text, it will change.</td>

Step 2: The swapImage() Function

Again, swapping images is as simple as assigning a new source attribute to the image. In our case, all the “checkboxes” will use one of two images: an “up” image, which is unchecked; and a “down” image, for when the item is checked. Since the image is always the same, we’ll declare the HTTP relative paths to those images in our function.

Next, we get the image that we want to swap via getElementById, taking the argument our onclick event handler sent to the function.

We assign the current source attribute of that image to a variable named theState. What we’ll get is the full HTTP path to the image — that is, http://www.domain.com/images/image.ext — instead of the HTTP relative path, such as images/image.ext.

So, we simply test to see whether we can find the up-state (not-checked) image in theState. If we can, we know the “checkbox” was previously unchecked, so we swap the source to be the checked image. If we don’t find the up-state image in theState, we know the image was “checked”, and we swap it back to the unchecked image.

function swapImage(imgID) {
	var imgUp = "images/1.jpg";
	var imgDown = "images/2.jpg";

	var theImage = document.getElementById(imgID);
	var theState = theImage.src;

	if(theState.indexOf(imgUp) != -1) {
		theImage.src = imgDown;
	}
	else {
		theImage.src = imgUp;
	}
}

And again, I prefer to preload images, so I add my stock preloading function to the page source:

function preloadImages() {
	for(var i = 0; i < arguments.length; i++) {
		var tmp = new Image();
		tmp.src = arguments[i];
	}
}

And add the script to the onload event handler for the BODY tag:

<body onload="preloadImages('images/2.jpg');">

And it’s as simple as that. You can see a working demo here:

http://demo.dougv.com/js_imgswap_checked/

Example 2: Get The “Checked” Values

While the previous example answers the question posed, it’s not as functional as knowing which images have been “checked” — information we might need to know in order to process a form.

Fortunately, by using getElementsByName, we can retrieve all of our pseudo-checkboxes, iterate through them, discover which are “checked” on the basis of their current source attributes, and add those checked items to an array — the same way HTML checkboxes return which items are checked.

Step 1: The HTML Modifications

The HTML for Example 2 is nearly the same as the HTML for Example 1, except that for each “checkbox” image, we add a name attribute that is the same for each image — the same way we would give the same name to all the HTML checkboxes we want grouped together.

<img id="item1" onclick="swapImage('item1')" src="images/1.jpg" alt="" />
<img id="item2" onclick="swapImage('item2')" src="images/1.jpg" alt="" />
<img id="item3" onclick="swapImage('item3')" src="images/1.jpg" alt="" />
<img id="item4" onclick="swapImage('item4')" src="images/1.jpg" alt="" />
<img id="item5" onclick="swapImage('item5')" src="images/1.jpg" alt="" />
<img id="item6" onclick="swapImage('item6')" src="images/1.jpg" alt="" />

For the purpose of this demo, I also add a DIV that will display which items are checked.

<div id="statusDiv">The following items are checked: none</div>

We recycle the same preloader function and body onload event handler call.

Step 2: Set Global JavaScript Variables

We modify the JavaScript by making the up-state and down-state image paths global variables. We also declare, as a global variable, the array which will hold the checked items.

var imgUp = "images/1.jpg";
var imgDown = "images/2.jpg";
var checkedItems = new Array();

Step 3: Add The getCheckedElements() Function To The swapImage() Function

By virtue of declaring the up-state and down-state images globally, we can remove those declarations from swapImage().

Instead, we’ll add to swapImage() a call to a new function, which we will call getCheckedElements(). We do that because every time we check an image on or off, we need to get a new listing of the checked items; so, since the swapImage() function is handling each click for us, it makes sense to call the new function there.

function swapImage(imgID) {
	var theImage = document.getElementById(imgID);
	var theState = theImage.src;

	if(theState.indexOf(imgUp) != -1) {
		theImage.src = imgDown;
	}
	else {
		theImage.src = imgUp;
	}
	getCheckedElements();
}

Step 4: The getCheckedElements() Function

The function that will tell us which images are “checked” begins by getting all the similarly named images via getElementsByName. That built-in function returns the images as an array. It generally places those items into the array in the order they appear in source code, but not always; so, be cognizant that your items might not be ordered the way you expect.

Next, we reset the length of the checkedItems array to 0, effectively clearing all current values.

Now, we iterate through all the check-images, looking at their source attributes. If the down-state (checked) image is the source, then the item is checked, and we add that check-image’s unique ID to the end of the checkedItems array. In effect, the image’s unique ID attribute acts as the value of the “checkbox.”

At this point, we now have populated the global checkedItems array with all the checked images; we can go ahead and use that however we want.

For this example, I’m just going to echo out all the checked items to a string, which I will then set as the innerHTML of the status DIV I created back in Step 1. You can safely delete that from the function if all you want is for the images to swap.

function getCheckedElements() {
	var imgArray = document.getElementsByName('checkboximg');
	checkedItems.length = 0;

	for(var i = 0; i < imgArray.length; i++) {
		var tmp = imgArray[i].src.toString();
		if(tmp.indexOf(imgDown) != -1) {
			checkedItems.push(imgArray[i].id.toString());
		}
	}

	var strOut = "<p>The following items are checked: ";
	if(checkedItems.length != 0) {
		strOut += checkedItems.toString();
	}
	else {
		strOut += "none";
	}
	strOut += "</p>";

	var theDiv = document.getElementById('statusDiv');
	theDiv.innerHTML = strOut
}

And that’s all there is to it! You can see a working demo here:

http://demo.dougv.com/js_imgswap_checked/example2.html

Example 3: Assign The Checked Images To HTML Checkboxes

The problem with having the “checked” images stored as a JavaScript array is that unless you intend to use JavaScript to post the checked images to a server via an AJAX request or the like, it’s not very handy. It would be far more convenient for us to be able to send the results to our server-side processing page (such as a PHP or ASP.NET script) as standard HTML elements.

We can do that by dynamically adding to the page new HTML checkboxes for each checked image to the form; to me, that’s overkill. It’s far easier to actually add an HTML checkbox for each check-image, and simply hide those boxes from the user via CSS.

Then, every time we click an image, we’ll iterate through the checkedItems array, checking each HTML checkbox that has a corresponding checked image.

And just to prove I’m doing the server-side processing via a regular HTML POST, I’ll create a seperate PHP page that will echo back which images — now, converted to checkboxes — were checked.

Step 1: Add The HTML Checkboxes

Again, for each image that we can check, we’ll add a regular HTML checkbox with the same value as the ID for the image.

<input lang="hide" name="cblist[]" type="checkbox" value="item1" />
<input lang="hide" name="cblist[]" type="checkbox" value="item2" />
<input lang="hide" name="cblist[]" type="checkbox" value="item3" />
<input lang="hide" name="cblist[]" type="checkbox" value="item4" />
<input lang="hide" name="cblist[]" type="checkbox" value="item5" />
<input lang="hide" name="cblist[]" type="checkbox" value="item6" />

Notice that each checkbox has the class “hide” associated with it. That CSS class simply sets the display for the items to none.

input.hide {
	display: none;
}

Step 2: Modify The getCheckedElements() JavaScript Action

The getCheckedElements() function is modified by replacing our previous text output routine with a new routine that gets all our hidden checkboxes via getElementsByName. Then, it unchecks all the elements, so we start with a clean slate.

We then see if the value of each checkbox corresponds to one of the checkedItems array cells; if so, we set that checkbox’s state to checked.

function getCheckedElements() {
	var imgArray = document.getElementsByName('checkboximg');
	checkedItems.length = 0;

	for(var i = 0; i < imgArray.length; i++) {
		var tmp = imgArray[i].src.toString();
		if(tmp.indexOf(imgDown) != -1) {
			checkedItems.push(imgArray[i].id.toString());
		}
	}

	var theBoxes = document.getElementsByName('cblist[]');
	for(var i = 0; i < theBoxes.length; i++) {
		theBoxes[i].checked = false;
		for(var x = 0; x < checkedItems.length; x++) {
			if(theBoxes[i].value == checkedItems[x]) {
				theBoxes[i].checked = true;
				break;
			}
		}
	}
}

Step 3: Add A Form Action And Submit Button

We assign our soon-to-be-described PHP handler page, echo.php, to the form’s action, and add a submit button to our form.

<form id="frmMain" method="post" action="echo.php">
	<table lang="theForm" cellspacing="0">
		<tr>
			<td><img src="images/1.jpg" id="item1" name="checkboximg" alt="" onclick="swapImage('item1')" /></td>
			<td onclick="swapImage('item1')">This is item 1. If you click on the icon to the left, or this text, it will change.</td>
		</tr>
		<tr>
			<td><img src="images/1.jpg" id="item2" name="checkboximg" alt="" onclick="swapImage('item2')" /></td>

			<td onclick="swapImage('item2')">This is item 2. If you click on the icon to the left, or this text, it will change.</td>
		</tr>
		<tr>
			<td><img src="images/1.jpg" id="item3" name="checkboximg" alt="" onclick="swapImage('item3')" /></td>
			<td onclick="swapImage('item3')">This is item 3. If you click on the icon to the left, or this text, it will change.</td>
		</tr>
		<tr>
			<td><img src="images/1.jpg" id="item4" name="checkboximg" alt="" onclick="swapImage('item4')" /></td>

			<td onclick="swapImage('item4')">This is item 4. If you click on the icon to the left, or this text, it will change.</td>
		</tr>
		<tr>
			<td><img src="images/1.jpg" id="item5" name="checkboximg" alt="" onclick="swapImage('item5')" /></td>
			<td onclick="swapImage('item5')">This is item 5. If you click on the icon to the left, or this text, it will change.</td>
		</tr>
		<tr>
			<td><img src="images/1.jpg" id="item6" name="checkboximg" alt="" onclick="swapImage('item6')" /></td>

			<td onclick="swapImage('item6')">This is item 6. If you click on the icon to the left, or this text, it will change.</td>
		</tr>
	</table>
	<input name="cblist[]" type="checkbox" value="item1" lang="hide" />
	<input name="cblist[]" type="checkbox" value="item2" lang="hide" />
	<input name="cblist[]" type="checkbox" value="item3" lang="hide" />
	<input name="cblist[]" type="checkbox" value="item4" lang="hide" />
	<input name="cblist[]" type="checkbox" value="item5" lang="hide" />

	<input name="cblist[]" type="checkbox" value="item6" lang="hide" />
	<p>Click the submit button to pass the checked items to a PHP page via standard HTML: <input name="submit" type="submit" value="Submit" /></p>
</form>

Step 4: The echo.php Page

The PHP page just needs to echo out any of the checked box values. I’ll first check to see if this page has been reached by post.

Then, I check the length of the checkboxes array. If the length is 0, I know nothing was checked and post that; otherwise, I use a foreach() statement to echo out the checked items.

if(isset($_POST['submit']) && strpos($_SERVER['HTTP_REFERER'], 'dougv.com') !== false) {
	if(count($_POST['cblist']) > 0) {
		echo "<p>You have checked the following items:</p>n";
		echo "<ul>n";
		foreach($_POST['cblist'] as $item) {
			echo "<li>$item</li>n";
		}
		echo "</ul>n";
	}
	else {
		echo "<p>There are no checked items.</p>n";
	}
}
else {
	echo "<p>You didn't post to this page from the example page. Please try again.</p>n";
}

And that’s all there is to that. You can see a working demo here: http://demo.dougv.com/js_imgswap_checked/example3.html

I distribute code under the GNU GPL. See Copyright & Attribution for details.

4 Comments

  1. Hi,
    this (almost) exactly what I was looking for, so a big thanks!
    One small question though, how hard would it be to change the code to have custom on and off images for each item? So something like item1_on.jpg, item1_off.jpg, item2_on.jpg etc.
    best regards,
    Janco

  2. @Janco: You may not have seen the original images due to some coding errors in the post, which I have just fixed. Take another look, as the up (off) state is the starting image, and the down (on) state is the changed image.

  3. Hi Doug, I don’t know if you’re still managing this page as it’s many years later, but can you give any insight into how I might be able to use different images for each checkbox? The way the code is now permits only 1 image; so for example, I wanted to create checkboxes as images that were each different, and when selected, darkened in color (by replacing the image with the same image, only darker), so it would be evident which image was selected by the user. Any way to modify the code to do this? Thanks in advance!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  • Check out the Commenting Guidelines before commenting, please!
  • Want to share code? Please put it into a GitHub Gist, CodePen or pastebin and link to that in your comment.
  • Just have a line or two of markup? Wrap them in an appropriate SyntaxHighlighter Evolved shortcode for your programming language, please!