span inside button, is not clickable in Firefox

My CODE


HTML:

<p id="console"></p>
<button>Click <span class="icon"></span>
</button>

JS:

$('.icon').click(function () {
    $('#console').html('Icon has been clicked');
    return false;
});

$('button').click(function () {
    $('#console').html('Button has been clicked');
});

CSS:

.icon {
    background-position: -96px 0;
    display: inline-block;
    width: 14px;
    height: 14px;
    margin-top: 1px;
    line-height: 14px;
    vertical-align: text-top;
    background-image: url("http://twitter.github.com/bootstrap/assets/img/glyphicons-halflings.png"); 
    background-repeat: no-repeat;
}

Demo

Problem


I am able to click on .icon in Chrome , but not in Firefox. When I click on .icon, it clicks on whole button.

Question:


Isnt my code valid ? If my code is valid, whats the solution to this problem.

What I have tried


  1. I have tried doing $('.icon').click() from console and it works perfectly in ff, so I guess the problem is that span is not clickable inside button.

  2. e.preventDefault() and e.stopPropagation are not working either.

  3. I've tried putting &nbsp; inside span but its not working either.


Refer to the spec, most notably the forbidden contents (in the SGML definition; for assistance reading that, look here): as, forms, form "controls" (input, select, etc), and fieldsets.

While you are correct in asserting that spans (and divs, etc) are legal contents of a button element, the illegal elements are all to do with having button content that does anything other than layout / styling.

I don't see anything in the spec precluding what you're trying to do, but I do see a lot discouraging it, and would be unsurprised if various browsers also "discouraged" that by not supporting it.

Which is to say: find another way to do what you want if you want to have cross-browser support. I don't understand what you're actually trying to do, so I don't think its possible to propose alternatives. I get that you want to respond differently to clicking on the button vs the icon -- but that's a (good, btw) demonstration of what you don't want to happen, not an explanation of an actual problem you want to solve.

One way might be to not use a button, and instead use another span or a div:

<p id="console"></p>
<div class="button_replace">Click <span class="icon"></span></div>
<script>
  $('.icon').click(function () {
    $('#console').html('Icon has been clicked');
    return false;
  });
  $('.button_replace').click(function () {
    $('#console').html('Button has been clicked');
  });
</script>

If you're here, maybe this solution will work for you, even though it's not really related directly to the question.

If you've applied a

  • $("button").click() listener, and
  • your button contains a <span> or any other <tag>, and
  • your .click callback function refers to $(this) (or even this)

Then, if you click on the button, this will likely be the top-most tag you CLICKED ON.

This will often, such as in my case, misattribute the caller, causing script errors.

Hope it helps someone out there!