Using Images as Labels in Internet Explorer

Internet Explorer has a bug where wrapping a label around an image doesn't work the same as if you wrap it around text.

Example:

<input type="checkbox" id="a"><label for="a"><img src="..."></label>

What the label does is create an association between its contents and a control on the page. In most browsers, clicking on text or an image within the label will give focus to the area. In the case of a radio button, it will select it and in the case of a checkbox, it'll alternate between the two states (checked and unchecked).

Internet Explorer, however, has a bug where clicking on an image inside a label tag does nothing. (Actually, I should say nothing useful because with radio buttons and checkboxes it looks like it tries to select the control but never does.)

What I've done is put together a quick bit of unobtrusive JavaScript to "fix" the problem. Albeit, only for people with JavaScript turned on.

window.onload = function(){
  if(document.all && navigator.appVersion.indexOf("MSIE")>-1 && navigator.appVersion.indexOf("Windows")>-1)
  {
    var a = document.getElementsByTagName("label");
    for(var i=0,j=a.length;i<j;i++){
      if(a[i].hasChildNodes && a[i].childNodes.item(0).tagName == "IMG")
      {
        a[i].childNodes.item(0).forid = a[i].htmlFor;
        a[i].childNodes.item(0).onclick = function(){
          var e = document.getElementById(this.forid);
          switch(e.type){
            case "radio": e.checked|=1;break;
            case "checkbox": e.checked=!e.checked;break;
            case "text": case "password": case "textarea": e.focus(); break;
          }
        }
      }
    }
  }
}

What the code does is loop through all labels on the page and checks whether the first child node is an image [1]. If it is then it attaches an onclick event handler which when run, checks to see what type of form control it's attached to and performs the expected action.

[1] While I don't have a specific need for it, it is theoretically possible to have the image not be the first child node within the label. The code would need to be expanded to locate where and how many images are inside a label and assign the event handler that way.

One additional caveat, this code would theoretically override any existing onclick event handler, so best to think about all the scenarios and plan!

Update on November 21, 2010: A jQuery solution provided by Eli Penner.

$("label img").live("click", function() {
  $("#" + $(this).parents("label").attr("for")).click();
});

Update on November 22, 2015: A CSS solution for IE11.

label img{
    pointer-events: none;
}
label{
    display: inline-block;
}

The inline-block ensures that the image gets wrapped properly so that it can be clicked on.

(Thanks to Saulius Žemaitaitis for letting me know about this.)

Published March 11, 2005 · Updated November 22, 2015
Categorized as JavaScript
Short URL: https://snook.ca/s/348

Conversation

12 Comments · RSS feed
Roger Johansson said on March 12, 2005

Just the other day I noticed this bug, and here's a solution. How did you know? ;-)

Wesley Walser said on March 12, 2005

I was reading the other day about being able to click on the labels (textual) of checkboxes to make a selection. I haven't found the javascript for it yet, but I know it's out there. http://pingomatic.com/ < there is a site that uses it...

Jonathan Snook said on March 12, 2005

Actually, for text-based labels, there's no javascript necessary. IE supports them correctly. All you need to do is specify the id of the input that the label belongs to. (like in the example I gave but instead of an image, it's text). The javascript is intended only to fix a bug in IE.

Matthijs said on September 07, 2005

Nice fix. I've slightly modified your code to allow more than one image to be in the label.

Changed the code in the IF statement to:

a[i].onclick = function(){
var e = document.getElementById(this.htmlFor);
switch(e.type){
case "radio": e.checked|=1;break;
case "checkbox": e.checked=!e.checked;break;
case "text": case "password": case "textarea": e.focus(); break;
}

This adds the onclick event to the LABEL itself, which seems to work very well in IE.

Chris Altman said on August 24, 2006

http://www.snook.ca/archives/javascript/using_images_as/

AWESOME Code! Thank you

Riddle said on October 09, 2006

Hi, I came up with CSS workaround for this bug - you can watch the demo because frankly, I don't think you understand Polish. ;-)

Best regards.

Tuning Marc said on October 17, 2006

Nice trick, seems to work very well in IE7.

Porter said on December 18, 2006

Many thanks! My need for an IE fix is very specific so I just use addEvent in-page, but this helped me confirm it wasn't my HTML or some other specific conflict, just another IE wonkyism.

Krishna said on January 17, 2007

hi,
You have done a good job. I am facing this problem and I got solution by this. So I am thankful to you. So keep doing such work.

Pete Graham said on April 16, 2007

Excellent solution, thanks a lot!

Yuri Teixeira said on May 21, 2007

I liked it... But it needs a little modification to fire onclick events of a checkbox, select, or text input. Here is my patched version of this script snipt that need to be modified:


switch (e.type) {
   case "radio": e.click(); break;
   case "checkbox": e.click(); break;
   case "text": case "password": case "textarea": e.focus(); break;
}

Best Regards

Conradson said on February 11, 2011

The Prototype solution :

Event.observe(window, 'load', function() {
if (Prototype.Browser.IE) {
var imgLabels = $$("label img");
imgLabels.each(function(eachImgLabel) {
Event.observe(eachImgLabel, "click", function() {
var radiolabel = eachImgLabel.ancestors()[0].readAttribute('for');
$(radiolabel).click();
});
});
}
});

Sorry, comments are closed for this post. If you have any further questions or comments, feel free to send them to me directly.