10
X

Quick Tip: Click Table Row to Trigger a Checkbox Click

read 57 comments

Somebody on the jQuery Google Group asked the other day about toggling a checkbox within a table row when the user clicked anywhere within the row. This can be a nice feature to have, and it's also very straightforward to implement.

The Basics

The one tricky part is that we don't want to trigger the click if the user clicks on the checkbox itself, because then it would effectively be clicked twice, once by the user and once programmatically. To avoid this, we can use the event argument inside the click handler. Let's take a look at how the code might be written:

JavaScript:
  1. $(document).ready(function() {
  2.   $('#rowclick1 tr').click(function(event) {
  3.     if (event.target.type !== 'checkbox') {
  4.       $(':checkbox', this).trigger('click');
  5.     }
  6.   });
  7. });

Line 3 makes sure that the type attribute of the target element is not "checkbox." If it isn't, then line 4 finds all checkboxes within the clicked table row (this) and clicks them.

Continue Reading Below

Give it a shot:

row 1
row 2
row 3

Adding a "Selected" Class

While we're at it, we can add a "selected" class to rows when they are clicked. This way, the user will have one more visual indicator that the checkbox has been checked. We'll use the .toggleClass() method so that it adds the class if it isn't there, and removes it if it is:

JavaScript:
  1. $(document).ready(function() {
  2.   $('#rowclick2 tr').click(function(event) {
  3.     $(this).toggleClass('selected');
  4.     if (event.target.type !== 'checkbox') {
  5.       $(':checkbox', this).trigger('click');
  6.     }
  7.   });
  8. });

Notice that the .toggleClass() line is outside of the if statement. We want the class to toggle whether the actual target of the click is on the checkbox or not.

row 1
row 2
row 3

If you look carefully at this table, you'll notice that the second row has a little problem. Since its checkbox is initially checked, the first click on that row adds the "selected" class while it also unchecks the checkbox.

Initializing the "Selected" Class

We can fix this problem by making sure that all rows that have a checked checkbox are given the "selected" class when the page loads:

JavaScript:
  1. $(document).ready(function() {
  2.   $('#rowclick3 tr')
  3.     .filter(':has(:checkbox:checked)')
  4.     .addClass('selected')
  5.     .end()
  6.     .click(function(event) {
  7.     $(this).toggleClass('selected');
  8.     if (event.target.type !== 'checkbox') {
  9.       $(':checkbox', this).trigger('click');
  10.     }
  11.   });
  12. });

Line 3 filters the matched set of table rows to include only those that have checked checkboxes. After the "selected" class is added to those rows, line 5 reverts the matched set to all rows (within #rowclick3). Then we carry on with binding the click handler to the rows. This example should work as expected:

row 1
row 2
row 3

These rows are also enhanced by a little CSS rule: .js #rowclick3 tr { cursor: default; }. This gives the entire row the same cursor as the checkbox. The rule is applied only if JavaScript is enabled (see my previous post for details).

Update

As of jQuery 1.3, the .toggleClass() part of this code doesn't appear to work. In fact, it is being fired twice on each click. The problem has arisen because event bubbling is now supported for the .trigger() method. As the documentation states, "All triggered events now bubble up the DOM tree. For example if you trigger an event on a [checkbox] then it will trigger on that element first, then on the parent element, and its parent, and so on up to the document."

So, how can we get the script working again the way it was intended? I have two solutions, and I welcome others.

Bind to the Checkbox

The first solution involves binding a click handler directly to the checkboxes for the .toggleClass(). In this way, we take advantage of the triggered event bubbling.

JavaScript:
  1. $(document).ready(function() {
  2.   $('#rowclick4 tr')
  3.     .filter(':has(:checkbox:checked)')
  4.     .addClass('selected')
  5.     .end()
  6.   .click(function(event) {
  7.     if (event.target.type !== 'checkbox') {
  8.       $(':checkbox', this).trigger('click');
  9.     }
  10.   })
  11.     .find(':checkbox')
  12.     .click(function(event) {
  13.       $(this).parents('tr:first').toggleClass('selected');
  14.     });    
  15. });

This fixes the problem, but I'm not crazy about it. It doubles the number of elements that have events bound to them, and I've been trying lately to reduce bound elements.

row 1
row 2
row 3

Change the checked Attribute

The second solution forgoes the click trigger in favor of simply changing the value of the checkbox's checked attribute.

JavaScript:
  1. $(document).ready(function() {
  2.   $('#rowclick5 tr')
  3.     .filter(':has(:checkbox:checked)')
  4.     .addClass('selected')
  5.     .end()
  6.   .click(function(event) {
  7.     $(this).toggleClass('selected');
  8.     if (event.target.type !== 'checkbox') {
  9.       $(':checkbox', this).attr('checked', function() {
  10.         return !this.checked;
  11.       });
  12.     }
  13.   });
  14. });

I used an anonymous function for the .attr() method's second argument because it seemed the most efficient way to toggle the value.

row 1
row 2
row 3

Both solutions work, but I prefer the second. Again, if you have a better idea, please let me know (by posting it in the comments).

With the updates, this hardly qualifies as a quick tip anymore. Oh well—back to our regularly scheduled blog post.…

Other Elements

This sort of thing can be done with other elements as well: clicking on a containing element to trigger the click of an element inside it. If we try to achieve this effect with links, though, we'll have to do it a little differently. Here is a quick example:

JavaScript:
  1. $(document).ready(function() {
  2.   $('div.biglink').click(function(event) {
  3.     window.location.href = $('a', this).attr('href');
  4.   });
  5. });

Keep in mind that this will send the user to the href of the first link inside the div.


comment feed

57 comments

  1. Hi,

    Your site is one of my favorites seen around blog explosion. Keep up the good work.
    I enjoy reading your blog. It is great to find someone who can find the fun things in life!
    I wish you all the best in all years. I look forward to developing a friendship and networking with you. Let me know if there is something I can do to assist you with your business free.

    With Regards,
    Karoly Domonyi
    http://www.ariestrade.com

  2. Very useful tut. Good Job.

    Thank you Karl

  3. elvisparsley

    Can you show only one row is ticked?
    When you tick one, then other should be unticked.

    • William Wallace

      I finally made the checkbox functionality just like radio buttons.

      http://jsfiddle.net/markcoleman/UYkXS/2/

      $("#emp_grid tbody tr").click(function(e) {
          $("#emp_grid tbody tr").removeClass("selected");
          var $checkbox = $(this).find(':checkbox');
          $("#emp_grid :checkbox").not($checkbox).removeAttr("checked");
          if (e.target.type == "checkbox") {
      
              // stop the bubbling to prevent firing the row's click event
              e.stopPropagation();
              $(this).filter(':has(:checkbox)').toggleClass('selected', $checkbox.attr('checked'));
          } else {
      
              
              $checkbox.attr('checked', !$checkbox.attr('checked'));
              $(this).filter(':has(:checkbox)').toggleClass('selected', $checkbox.attr('checked'));
          }
      });
      
  4. Mark Mulder

    You should use a radio button for that Elvisparsley, it only allows one to be clicked.

  5. Julian

    Remember to always use with form fields!

  6. Julian

    Remember to always use <label> with form fields!

  7. buaziz

    exactly what am looking for.

    i have a quick question

    when i check the box by script and that checkbox has a trigger event associated with it, the event is not fired.
    but it fires normally when the user manually checks the box.

    how do i remedy that.

    thanks.

  8. Bohdan Ganicky

    Nice and clean as usual, thanks Karl :)

  9. elvisparsley,
    I'm with Mark Mulder on that one. Use radio buttons, and give them the same name attribute, and you'll be set.

    Julian,
    You're absolutely right. I should have noted that in the tutorial. I was being sloppy with the structure of the HTML for the sake of "quickness" in this quick tip.

  10. buaziz,

    I'm not able to reproduce the problem you're having. Could you please take a look at this demo and let me know if I've misunderstood what you're trying to do?

  11. I could see tossing this in there:

    
    $(".rowclick td").css("cursor","pointer");
    

    Just to visually indicate the table cells are indeed clickable =)

  12. Hey Chris,
    Glad to see you here, and thanks for the comment!

    I actually did something similar for the third example, by adding a "JavaScript-enabled" rule to the stylesheet: .js #rowclick3 tr { cursor: default; }.

    I had gone back and forth between "pointer" and "default" but ended up going with "default" because that is what the checkbox gets, and I wanted to extend the functionality of the checkbox. Also, I wasn't sure if "pointer" would lead the user to believe that the cell will act like a link. Anyway, I don't feel strongly one way or the other.

  13. Sure I can see that. I find it kind of funny how browsers don't give some obviously-clickable input elements a pointer cursor. Like inputs with a type of "image" (like your submit comment button below), get a pointer. While inputs with a type of "submit" do not. Checkboxes also apparently get the "do not" treatment.

  14. Henry Taylor

    Will this work on table rows created by Jquery commands, gotten from an Ajax request? I have such a table and this code isn't working on it. I don't know whether it's because I'm creating the rows dynamically or if I've got another problem.

  15. Rico Chen

    This site really rocks! Nice, really nice. I used this technique on one of my new projects and it impressed my boss a lot. Thanks Karl.

  16. Web Agentur

    Thank you ... this tutorial has me very helped.

  17. Hi Henry, unfortunately this will only work on rows that are in the DOM at the time the method is invoked — $(document).ready().

    There are a few ways around this issue, including a couple plugins. This jQuery FAQ topic should help, as should my two "Working with Events" articles (part 1, part 2).

  18. I'm having a tough time with this script. It seems that if I have a lot of table rows (let's say 1500), then the page takes a long time to clean up when I'm trying to either refresh or browse to another page. Does Jquery run through all the elements and unbind everything that it bound during the script before letting the user move on to another page?

    Luke Brookhart

    • Hi Luke,
      Yes, jQuery unbinds everything when the document is unloaded. This helps prevent memory leaks, especially in IE.

      To avoid the problem you're experiencing, you can use event delegation. In jQuery 1.3, this will be easy to do with the new .live() method. But until then, you can do something like this for the click handler, attaching it to the table instead of each row:

      $('table').click(function(event) {
        var $tgt = $(event.target),
          $thisRow = ($tgt.is('tr') && $tgt) 
          || ($tgt.parents('tr').length && $tgt.parents('tr:first')) 
          || null;
        
        if ($thisRow) {
          $thisRow.toggleClass('selected');          
          if (!$tgt.is(':checkbox')) {
            $(':checkbox', $thisRow).trigger('click');
          }
        }
      });
      

      Hope that helps.

      • 
        if (!$tgt.is('td')) {
            $thisRow.toggleClass('selected');					
        }
         

        Added this check to avoid toggling the class twice. It works but what is the best way to do it? Using jQuery v1.3.1.

  19. Kris

    In answer to Elvispresley, I came up with the below code. Just replacing 'checkbox' in the code with 'radio', and having radio buttons the same name doesn't work - if you select one radio box then select another, the first will still have the 'selected' class turned on, so first you have to removeClass on all radio boxes, then toggle it for the current one.

          
    $(document).ready(function()
          {
          $(':radio, tr').filter(':has(:radio:selected)').end().click(function(event)
              {
                  //if the user didn't click on the checkbox itself, check it
                       if (event.target.type !== 'radio')
                       {
                       $(':radio', this).trigger('click');
                       }
                  $(':radio, tr').removeClass('selected');
                  $(this).toggleClass('selected');
              });
          });
    
    • Jens

      Hi Kris,

      thx for the provided solution.
      How do I add the "selected" class to the tr? It does not work for me...

  20. Arthur Corenzan
    $(".entry").click(function(event) {
    		$(this).toggleClass("active");
    		if(event.target.type !== "checkbox") {
    			$(":checkbox", this).trigger("click");
    		}
    	});

    This method is triggering a click on my div.entry when it clicks on my checkbox inside div.
    So the toggleClass is working twice. I could see it alerting something inside that function, while it waits my click on OK, I can see that my div now has the active class, after I click OK, it displays alert again and its class is gone.

  21. Lucas

    hi people, how can i do that when the user click, for example in the first record, that this click don´t check the checkbox, in this row i will only allow to check the checkbox only clicking the checkbox... any ideas? thanks!

  22. guru

    How to use this jquery in a table. I am a new web developer If you explain this in a html file format it will be easier for me to use. could you give the code example with table (tr td ) etc., I don't know where to call

    $(document).ready(function() {
      $('#rowclick1 tr').click(function(event) {
        if (event.target.type !== 'checkbox') {
          $(':checkbox', this).trigger('click');
        }
      });
    });
    

    such codes in a html page. Please give the demo as user-friendly given like http://www.jquery.com like

    <html>
      <head>
        <script type="text/javascript">
        $(document).ready(function(){
    
          $("button").click(function () {
            $("p").slideToggle("slow");
          });
    
        });
        </script>
        <style type="text/css">
          p { width:400px; }
        </style>
        
      </head>
      <body>
        <button>Toggle</button>
        <p>This is the paragraph to end all paragraphs.  You
        should feel <em>lucky</em> to have seen such a paragraph in
        your life.  Congratulations!</p>
      </body>  
    </html>  
    
  23. An example of toggling the checkbox and not triggering two events.
    And toggles row class in jQuery 1.3


    $("table body tr").live("click", function(event) {
    $(this).toggleClass("selected");
    if (event.target.type !== "checkbox") {
    checkbox = $(":checkbox", this);
    checkbox.attr("checked", checkbox.is(':not(:checked)'));
    }
    });

  24. Hillar, your code was close but doesn't check the status of the checkbox before applying the selected class, resulting in unpredictable results

    Just a case of keeping some of the original code to run that preliminary check.

    Thanks Karl.

    $('table.checkbox tr')
    .filter(':has(:checkbox:checked)')
    .addClass('selected')
    .end()
    .live('click', function(event)
    {
    $(this).toggleClass("selected");

    if (event.target.type !== "checkbox")
    {
    checkbox = $(":checkbox", this);
    checkbox.attr("checked", checkbox.is(':not(:checked)'));
    }
    });

  25. Tom

    Great code, one thing I'm stuck on is if you have a link in your tr how do you stop the onclick event triggering on that td?

  26. Josh

    I'm new to jQuery, so could someone explain why this works

    
    $('#table_1 tr').click(function(event) {
         if (event.target.type != 'checkbox' && event.target.nodeName != 'LABEL') {
              $('input:checkbox', this).trigger('click');
         }
    });
    

    and this doesn't

    
    $('#table_1 tr').click(function(event) {
         if (event.target.nodeName!= 'CHECKBOX' && event.target.nodeName != 'LABEL') {
              $('input:checkbox', this).trigger('click');
         }
    });
    

    Is the former the best way to avoid triggering the event when a label is clicked?

    • Hi Josh,

      There is no such nodeName as checkbox. The former code sample is looking for an element with type="checkbox", so it matches all <input type="checkbox"> elements.

  27. Dylan MacDonald

    I tried almost every example here and it didn't work as advertised. Sometimes I got the hover effcet, sometimes the select effect, sometimes the checkbox was checked, but never all three. What am I doing wrong?

    
    $(".productGrid.samplesGrid ul li")
    			.filter(':has(:checkbox:checked)')
    			.addClass('selected')
    			.end()
    			.live('click', function(event)
    			{
    			$(this).toggleClass("selected");
    
    			if (event.target.type !== "checkbox")
    			{
    			checkbox = $(":checkbox", this);
    			checkbox.attr("checked", checkbox.is(':not(:checked)'));
    			}
    			});
    

    and yes this is included within a document.ready function in my code.

    Thanks.

    • Dylan MacDonald

      Sorry forget my allusion to the hover effect. It's the select and checked that doesn't work altogether.

      • Hey, no problem, Dylan. Let me guess ... you're clicking on labels? If that's the case, then you need to add this at the end of that script:

              if (event.target.nodeName === 'LABEL') {
                return false;
              }
        

        I put together a quick demo for you. Let me know if it still doesn't work.

  28. Rob

    I have a table of data, including one cell containing an important number.

    When I click on a row, or a cell containing a href in that rowrow, how can I use this number, in a function call? (It's actually an ajax call, but I guess that's not important).

    Thanks for any help.

    • Rob

      To make it clear, there is an important number in column 1 in each row. The table is generated by PHP, so I can use this number elsewhere if needed.

  29. Joseph Buarao

    A really Like this site.. but i want to have a printable copy of this tutorials , could you please send it to me.. Actually Im using mootools, but i want to try jquery because i want to find out which better..

  30. Rizky

    Nice tip.. Really saves me a lot of time :D

    Btw, I'm having trouble implementing this with a "check all" button that selects and highlights all rows.

    my script is like this:

    $('input.checkall').click(function() {
      $(this).parents('table').find(':checkbox').attr('checked', this.checked);
      $(this).parents('table').find('tbody tr:not(.selected)').toggleClass('selected');
    });
    

    But when I uncheck the "select all" checkbox all the table rows are still highlighted.
    I know the problem is on the 'tbody tr:not(.selected)' selector. But can somebody point me to the right direction? :D

    Thx.

    • Rizky, you need to remove "dot". Try this;

      $('input.checkall').click(function() {
      $(this).parents('table').find(':checkbox').attr('checked', this.checked);
      $(this).parents('table').find('tbody tr:not(selected)').toggleClass('selected');
      });

  31. shwebdev

    I too have the same problem as TOM. How do you stop a href link from triggering the check/uncheck event if its inside the TR?

    • shwebdev

      I added this to the bottom of my script to fix links within the TR


      $("a").bind("click", function(e) {
      e.stopPropagation();
      });

  32. That's awesome, thanks! And how about 1 click to select the whole column?

  33. Uday

    I am new to jquery, how can i skip the disabled elements in the table, to avoid the toggel (checked and unchecked).

    • Hi Uday,

      Something like this would work:

      
      $(document).ready(function() {
        // use your own selector in the next line
        var $rows = $('#sometable tr');
      
        $rows.filter(function() {
          return !!$(this).find(':checkbox:checked').not(':disabled').length;
        }).addClass('selected');
      
        $rows.click(function(event) {
          if ( $(this).find(':checkbox').is(':disabled') ) {
            return false;
          }
          $(this).toggleClass('selected');
          if (event.target.type !== 'checkbox') {
            $(this).find(':checkbox').attr('checked', function() {
              return !this.checked;
            });
          }
        });
      });
      • Uday

        Thank you Karl, it's working :)

      • Agustin

        This is a nice code, worked perfectly! What If I wanna reset all the form?

        $("#textlink").click(function(){$("myForm input:checkbox").removeAttr('checked')

        With this I can only reset the checkboxes but how I can also remove the "selected" class?

        A simple .removeClass('selected'); doesn't work!

        Thanks in advance :)

  34. Hi Karl:
    Great expertise, and great help throughout! Thank you. I am not sure, if this is not common or you had addressed above (and I missed), I would like an example of table with both 'sortable columns ' and 'selectable rows' . Is that possible at all?
    Thanks in advance.

  35. leiyangkai

    Dear Friend:
    i really need your help , i want to do something like this :
    first checkbox hidden , and when i click the any other tr area . and the checkbox will be showed . and add the background in the area . and the checkbox must be checked .
    when i click the tr area second time that the checkbox will be hidden.
    looking forward to your answer , thanks so much and best wishes to you .

  36. Thank you. This is one of a few tutorials which are understandable AND work right away..!

  37. This will work for radio buttons. any suggestion?

    
    $(document).ready(function() {
      $('.row tr')
     .filter(':has(:radio:checked)')
      .end()
      .click(function(event) {
      $('.row tr').removeClass('selected');
      $(this).addClass('selected');
     if (event.target.type !== 'radio') {
       $(':radio', this).attr('checked', 'true')
     }
      });
    });
    
    
  38. DanDan

    Many thanks, have this working great with the jQuery DataTables plugin. http://www.datatables.net

11 Pings

  1. [...] Quick Tip: Click Table Row to Trigger a CheckBox Click (Karl Swedberg) [...]

  2. [...] Quick Tip: Click Table Row to Trigger a Checkbox Click » Learning jQuery - Tutorials and Informatio... (tags: table jquery javascript) [...]

  3. learning | Digg hot tags

    [...] Vote Quick Tip: Click Table Row to Trigger a Checkbox Click [...]

  4. [...] jQuery presents Quick Tip: Click Table Row to Trigger a Checkbox Click Somebody on the jQuery Google Group asked the other day about toggling a checkbox within a table [...]

  5. [...] Click Table Row to Trigger a Checkbox Click This tutorial explains how to toggle a checkbox within a table row when the user clicks anywhere within the row. This technique can be implemented with other elements as well, such as clicking on a containing element to trigger the click of an element inside it. [...]

  6. jQuery HTML Table Toolbox — 36 façons de «dresser la table» avec jQuery

    [...] Click Table Row to Trigger a Checkbox Click [...]

  7. jQuery HTML Table Toolbox | SeanBurdick

    [...] Click Table Row to Trigger a Checkbox ClickThis tutorial explains how to toggle a checkbox within a table row when the user clicks anywhere within the row. This technique can be implemented with other elements as well, such as clicking on a containing element to trigger the click of an element inside it. [...]

  8. jQuery HTML Table Toolbox « wwwba

    [...] Click Table Row to Trigger a Checkbox Click This tutorial explains how to toggle a checkbox within a table row when the user clicks anywhere within the row. This technique can be implemented with other elements as well, such as clicking on a containing element to trigger the click of an element inside it. [...]

  9. jQuery Table Plugins | Active Lancer - Free Web Resources and Open Source Tutorials

    [...] Click Table Row to Trigger a Checkbox Click This tutorial explains how to toggle a checkbox within a table row when the user clicks anywhere within the row. This technique can be implemented with other elements as well, such as clicking on a containing element to trigger the click of an element inside it. [...]

  10. [...] Click Table Row to Trigger a Checkbox ClickThis tutorial explains how to toggle a checkbox within a table row when the user clicks anywhere within the row. This technique can be implemented with other elements as well, such as clicking on a containing element to trigger the click of an element inside it. [...]

Sorry, but comments for this entry are now closed.