Resizable Table Columns with jQuery UI

When I had the pleasure to work on a Web User Interface (UI) components library, I tried to optimize the client-side performance of a data table component providing Windows Explorer-like resizable columns. It turned out that the JavaScripts for this feature performed very poorly on an application screen displaying a table with more than 40 columns. The initialization of all the scripts took more than one second. The in-house developed script for the resizing needed most of the time since it was calculating the widths of many DOM elements. Read in the following how I managed to get the jQuery UI Resizable plugin running on a table with proper HTML and how it speeded up the initialization time by 2/3 compared to our previous native scripts.


jQuery Plugins

We had the lucky requirement that lovely Internet Explorer 6 should be still supported. So I considered it as good idea to use JavaScript libraries which would handle cross-browser issues for us, now and in future. Our component library already integrated jQuery, hence I did some research on available plugins and found nice ones, such as:

  • .dataTable(). Simple usage, but resizing behavior is a bit odd. It resizes also other columns since it does not increase the table size. Also the initialization time of 50ms in IE9 for only five columns is not really convincing.
  • kiketable.colsizable. Actually looked very promising and incredibly fast. Unfortunately, does not work properly in IE (labels disappeared when the column size was too less) and did not work well together with our other scripts. Another drawback was that the last script update has been three years ago only.
  • Ingrid. The linked example takes more than 120ms on IE9 for only four columns, whereas I could not figure out how much of the time goes for the resizable columns. One issue with this script is that it does not update the table’s COLGROUP elements, but directly the TH elements. However, our table component rendered the widths always at the COL elements, and this would be also the only right place in my opinion.
  • colResizable. Again, resizes only TH elements and does not increase the table size without custom enhancements. Not as fast as the kiketable plugin.

Some more resources for your own evaluation:

jQuery UI Resizable

I eventually found a plugin which is widely used, tested, which performs well and comes from the guys who really have done a great job so far: jQuery UI Resizable. The only problem with this widget is that it can resize any DOM element, but TH elements (at least IE6+ has issues, it works with Chrome). There are workarounds with inner DIV elements, but we want proper HTML with size specifications in the COLGROUP area so that also big tables can be rendered very fast, don’t we?

The solution:

  • The HTML table specifies the initial width in its COLGROUP area and has CSS property table-layout:fixed.
  • Decorate TH elements with jQuery UI’s .resizable().
  • On resizing start: Find the matching COL element of active TH and remember original width.
  • On resizing: Calculate the resize delta and update (increase/decrease) the selected COL element. This will resize the whole column with every browser.

Implementation

Let us see some code. So you have your table in proper HTML:

<table class="resizable">
  <caption>Data Table with resizable columns</caption>
  <colgroup> 
    <col style="width: 100px;" /> 
	<col style="width: 150px;" /> 
	<col style="width: 100px;" /> 
  </colgroup>
  <thead>
    <tr class="colHeaders">
      <th>Column 1</th>
      <th>Column 2</th>
      <th>Column 3</th>
    </tr>
  </thead>
  <tbody>
  <tr>
    <td>Row 1, col 1</td>
    <td>Row 1, col 2</td>
    <td>Row 1, col 3</td>
  </tr>
  </tbody>
</table>

And this is, in short, how you get jQuery UI Resizable running on it:

$(".resizable th").resizable({
 handles: "e",

 // set correct COL element and original size
 start: function(event, ui) {
   var colIndex = ui.helper.index() + 1;
   colElement = table.find("colgroup > col:nth-child(" +
     colIndex + ")");

  // get col width (faster than .width() on IE)
  colWidth = parseInt(colElement.get(0).style.width, 10);
  originalSize = ui.size.width;
 },

 // set COL width
 resize: function(event, ui) {
   var resizeDelta = ui.size.width - originalSize;

   var newColWidth = colWidth + resizeDelta;
   colElement.width(newColWidth);

   // height must be set in order to prevent IE9 to set wrong height
   $(this).css("height", "auto");
 }
});

Optimization

The code can now be enhanced by

  • Encapsulating the code into a separate jQuery widget in order to improve maintainability.
  • Adding a “scroll container” around table which prevents the user to enlarge the whole page when he increases one column. It is simply a surrounding DIV with CSS property “overflow:auto”.
  • Calculating the column header label width and setting it as minimum width for resizing.
  • Already render the resizing helper DIV in the initial HTML markup rather than letting jQuery UI generating the nodes. On our large table, this saved 2 ms per column in IE8!

Performance

I know that you also love numbers, so here are some profiling results of this solution:

HTML table with 20 columns and 10 rows.
CPU: Intel i7, 2.2GHz
jQuery version: 1.7.2
jQuery UI (all) version: 1.8.21

Browser Resizable Script Init jQuery UI Library Init
IE 9 40 ms 5 ms*
Chrome 20 20 ms 45 ms
Safari 5 26 ms 45 ms
Firefox 14 38 ms 37 ms

* One should not always trust the IE’s in-built profiler…

Demo

Et voila, see the complete code and demo.

Update 2 May, 2013: Updated Script now also supports jQuery 1.8+

Update 6 June, 2014: License information
Please feel free to use my code snippets of this blog article and the linked jsfiddle. The code is licensed under the MIT license.

Advertisements

Tags: , , , , ,

26 responses to “Resizable Table Columns with jQuery UI”

  1. Linda says :

    The demo doesn’t seem to work with Firefox 17.0.1. Am I missing something? It worked properly in Safari.

    Thanks!

    • Ingo.Hofmann says :

      Hi Linda,
      Thanks for the hint. I can confirm that the linked demo was not working anymore with Firefox 17. As usual when having cross-browser issues, there is a “stupid” yet easy fix: Just add none-breaking spaces to the empty DIV elements with class “ui-resizable-e”. It looks like the new Firefox treats empty elements differently now. I am going to update the demo with this fix in a second.

  2. Sam says :

    Thanks for the tips But FYI: at least in chrome 25 (with jquery ui 1.10.1),

    resizing directly using jqueryui, aka, $(‘th’).resizable() ,does work properly, as long as one is careful that other elements in the column (the s and s) do not have width specified.

    One might also need to add work-break fo columns narrower (which is really an orthogonal issue).

    • Ingo.Hofmann says :

      Hi Sam,
      Thanks for the comment.
      My described snippet actually resizes the table’s COL elements, hence it _should_ not lead to issues when having fixed width elements in your table, as long as you set the CSS “overflow” property for cells.
      I created a version with a 100px wide DIV in one column and it still works for me: http://jsfiddle.net/aMdf6/325/
      Maybe you can also create a version which shows the problem that you are having?

  3. bogdan says :

    with newer versions of jquery(1.8), this widget doesn’t work in firefox

    • Ingo.Hofmann says :

      Thanks, Bogdan. That is, because jQuery removed the ability to test for the user agent. I made a quick fix on the demo, so that it works now again with jQuery 1.91 and jQuery UI 1.9.2.

  4. Eng says :

    Hi Info – this helped a lot. Any way to prevent new table from being smaller than the original table width?

  5. Bhaskar says :

    I am using the following JQuery versions.. The demo code is not working in asp.net environment. Solicit your help.

    • Ingo.Hofmann says :

      Hi Bhaskar,
      which version are you using? For me, it is working fine also with latest jQuery 2.0.2.
      It is JavaScript, so the underlying server technology doesn’t matter.

  6. Mauricio says :

    Hi,

    I tried your fiddle http://jsfiddle.net/aMdf6/325/ … but is not working from in firefox 23.0.1 nor IE9

  7. Denyo says :

    Great post!

  8. Christian says :

    Hi, what about any license usage? I could not find license information in your code.

    Cheers,
    Christian

    • Ingo.Hofmann says :

      Hi Christian,
      you’re right, license information is missing.
      Please feel free to use my code. I hereby put it under a MIT license, which allows you to use and modify it as per your wishes.
      jQuery and jQuery-UI are MIT licensed as well (as of the date this comment is written).

  9. irvan says :

    i am tried to copy your code from http://jsfiddle.net/aMdf6/325/ butthis to my local computer but this script not working. (using FF version 33, jquery-ui-1.9.2.js). would you like to send me complete example code via my email? thank you very much

    Cheers,
    irvan

  10. Ksenia says :

    Hallo Ingo,
    thank you very much for your post – it has helped me a lot!
    However, when i tried your code with the newest jquery-ui-1.11.2 and jquery 2.1.1 it didn’t work. (I use FF v.33)
    Probably you know the workaround for this case? 🙂

    Greetings from Dresden,
    Ksenia

    • Ingo.Hofmann says :

      Hallo Ksenia,
      Glad to hear that my post is helpful for you.
      I just retested and could not find any problem with latest Firefox 33.1.1 + jQuery 2.1.0 + jQuery-UI 1.11.2.
      Do you get any error message?
      Viele Grüsse aus Zürich
      Ingo

      • Ksenia says :

        Hallo Ingo,

        thank you for retesting it, i have also checked my code and finally i found out that i simply forgot somehow to insert into my css file the ”handle for FF”. Also i was a little bit confused by JSFiddle: when i choose jquery 2.1.0 in drop box from the left side and then select “Update” or “Run” – after this i could not resize the table columns any more….Anyway, now everything is Ok 🙂

        Mach dir einen tollen Tag!..und Danke für deine Hilfe!
        Viele Grüße,
        Ksenia

  11. Chandrashekar says :

    Hi Ingo

    Thank you very much for your post – it has helped me a lot!

    I have a different question but very much related.

    I am adding a new column to the table via jquery. I am unable to resize the newly added columns.

    Any inputs on this one?

    Thanks in advance.

  12. Andrej Gajdos (@Andrej_Gajdos) says :

    Does anybody have this solution with draggable cells in table body, not only in header? Btw thanks for sharing this solution 🙂

  13. Brys says :

    Thanks for writing this up; It really helped me to get started.

    I’d like to add for anyone else who find it useful that jQuery ui has added a property, alsoResize, that can make the cols and th’s size together. It really helps performance to define this in the initial configuration rather than to find the respective col element on each resize event.

    http://api.jqueryui.com/resizable/#option-alsoResize

  14. Wind Bridges says :

    Hi, Ingo! Your code really helped me a lot, thank you. Could you please give me a hint, how it can be modified to work on mobile browsers? Currently I checked it in Chrome in Android, it just dragging a whole table when I try to resize a column.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: