Tuesday 10th May, 2011

Creating beautiful and functional tables with DataTables

Update - 13th February 2012: This article was updated for DataTables 1.9 which uses A tags rather than SPAN for pagination controls.

DataTables has a wealth of features enabled by default (as can be seen in the zero-configuration example) but the example stylesheets that come in the DataTables package are intentionally rather basic, and there will be times you wish to integrate the look and feel of the table a lot more than the default style allows.

Fortunately styling a DataTables table is actually a relatively simple prospect and I'll show how to build the style up so that your table looks like the one shown below in this post. In this post I'll use only very basic initialisation of DataTables and concentrate on just nice CSS styling! I'll be building on the fine work of Inayaili de Leon for this example, and we will end up with a table which looks like this:

The table

First things first - we need a table to show. You'll no doubt have your own that you wish to style, but in this example I'm going to use some statistics from the Scottish Government about student numbers. Not the most inspiring of information perhaps, but a perfect example of a statistics table which can be presented on a web-site. The basic unstyled and unscripted table looks like this:

<table id="example" border="0" cellpadding="0" cellspacing="0" class="pretty">
    <thead>
        <tr>
            <th rowspan="2">Local authority</th>
            <th colspan="7">Scottish domiciled students in HE</th>
        </tr>
        <tr>
            <th>2005-06</th>
            <th>2006-07</th>
            <th>2007-08</th>
            <th>2008-09</th>
            <th>2009-10</th>
            <th>% change<br>over last year</th>
            <th>% change<br>since 2005-06</th>
        </tr>
    </thead>
    <tfoot>
        <tr>
            <th scope="row">Total</th>
            <td>212.920</td>
            <td>214.860</td>
            <td>206.390</td>
            <td>207.535</td>
            <td>213.210</td>
            <td>2.7</td>
            <td>0.1</td>
        </tr>
    </tfoot>
    <tbody>
        <tr>
            <th scope="row">Aberdeen City</th>
            <td>9.750</td>
            <td>9.850</td>
            <td>9.945</td>
            <td>9.945</td>
            <td>10.080</td>
            <td>1.4</td>
            <td>3.4</td>
        </tr>
        ...
    </tbody>
</table>

Note that because of the TH elements in the table body rows, this example uses DataTables 1.8, where the ability to consume TH elements in the body is a new feature. The full basic page that we are going to work with is available here.

Style and scripting base

In order to preserve our sanity and provide a common baseline for styling the table, I'm going to include the YUI 3 reset stylesheet. This stylesheet basically strips the built-in default styles from a viewing web-browser to give a common starting point for styling across all browsers. This is particularly useful with tables since browsers can often have different defaults styles for various elements. This reset stylesheet is included using the following HTML:

<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/3.3.0/build/cssreset/reset-min.css">

I've also added some basic styles to my page in order to provide a little bit of a framework for us to work with (font-size, content width etc).

Next we include and execute the Javascript required to enhance the table with DataTables. This is done by including jQuery and DataTables, followed by initialising DataTables. In this particular case I've chosen to use the built-in "full_numbers" pagination style by specifying the sPaginationType parameter. This is all the Javascript that we need to setup our table.

<script type="text/javascript" language="javascript" src="../../media/js/jquery.js"></script>
<script type="text/javascript" language="javascript" src="../../media/js/jquery.dataTables.js"></script>
<script type="text/javascript" charset="utf-8">
    $(document).ready(function() {
        $('#example').dataTable( {
            "sPaginationType": "full_numbers"
        } );
    } );
</script>

DataTables framework

Now we can actually start styling our table and its components. The first thing to look at here is the positioning of the various table controls that are added by DataTables. These are the elements which control and show information about the table:

  • Table length control - DIV class "dataTables_length"
  • Filtering input - DIV class "dataTables_filter"
  • Information output - DIV class "dataTables_info"
  • Pagination controls - DIV class "dataTables_paginate"

The order of these elements in the DOM is controlled by the sDom parameter, which can directly effect how you will style the elements. In this case we are using the default setting for sDom so the order is the same as the list above, with the table inserted between the filtering and information elements. To position the various control elements we can float them into position using the following CSS. Note I've also included highlighting colours to make it easy to see where each element is. In additional this I've included a little padding for the various elements, so they visually fit around the table nicely.

div.dataTables_length {
    float: left;
    background-color: red;
}

div.dataTables_filter {
    float: right;
    background-color: green;
}

div.dataTables_info {
    float: left;
    background-color: blue;
}

div.dataTables_paginate {
    float: right;
    background-color: yellow;
}

div.dataTables_length,
div.dataTables_filter,
div.dataTables_paginate,
div.dataTables_info {
    padding: 6px;
}

Also because we are using floating elements we need to consider clearing them. In this case the table needs to clear the paging length and filtering inputs, while any content that follows the table needs to clear the pagination and information elements. For the former we can use a simple clear: both, but for the latter we can use a self-clearing technique.

table.pretty {
    clear: both;
}

/* Self clearing - */
div.dataTables_wrapper:after {
    content: ".";
    display: block;
    clear: both;
    visibility: hidden;
    line-height: 0;
    height: 0;
}
html[xmlns] .dataTables_wrapper { display: block; }
* html .dataTables_wrapper { height: 1%; }

Table styles

Next up is adding styles to the table itself so that is actually starts to look quite good. In the first instance we want to set the table width to be 100% of the DataTables container element (since by default the browser will contract its width to the minimum required size, as can be seeing in the above example). Then we want to add some padding and a white border to the cells in the table. Note that the YUI reset stylesheet sets table { border-collapse: collapse } so we don't need to worry about cell borders being wider than 1px.

table.pretty {
    width: 100%;
    clear: both;
}

table.pretty td,
table.pretty th {
    padding: 5px;
    border: 1px solid #fff;
}

For the header cells we simply want to add a background colour and align the text to the center of the cells. We do this thus:

/* Header cells */
table.pretty thead th {
    text-align: center;
    background: #66a9bd;
}

In the table body we have a mix of TH and TD elements to give semantic meaning to the table's markup. This can also be very useful for visual styling allowing the CSS selectors to target cells as we need. In this case the TH elements, which give the row header and the TD elements for the row contents are to be given background colours and different text alignments. Note also that DataTables adds 'odd' and 'even' classes to the TR elements in the table allowing zebra stripes to added easily to the table (in this case we just use the 'odd' class).

/* Body cells */
table.pretty tbody th {
    text-align: left;
    background: #91c5d4;
}

table.pretty tbody td {
    text-align: center;
    background: #d5eaf0;
}

table.pretty tbody tr.odd td { 
    background: #bcd9e1;
}

The footer, like the body, has a mix of TH and TD elements again to provide semantic meaning. Like the other cells in the table we add a background colour - in this case a green colour, to give emphasis that this row has importance.

/* Footer cells */  
table.pretty tfoot th {
    background: #b0cc7f;
    text-align: left;
}

table.pretty tfoot td {
    background: #d7e1c5;
    text-align: center;
    font-weight: bold;
}

Finally we add a background colour to the DIV element that DataTables puts onto the page to contain the table and all of its control elements. This effectively provides a header and footer to the table:

div.dataTables_wrapper {
    background-color: #719ba7;
}

Sorting and paging

We are nearly there - so very close! Just two more points to consider: the sorting and paging controls of the table that DataTables adds. For the sorting, this is visually controlled by the classes by the classes that DataTables has put onto the TH elements for each column.

  • th.sorting_asc - table is sorted on this column - ascending
  • th.sorting_desc - table is sorted on this column - descending
  • th.sorting - table can be sorted on this column

To show this visually, we can use a background image to indicate that a column is being sorted upon or that the column can be sorted by clicking on it.

table.pretty thead th.sorting_asc {
    background: #66A9BD url('images/sort_asc.png') no-repeat right center;
}

table.pretty thead th.sorting_desc {
    background: #66A9BD url('images/sort_desc.png') no-repeat right center;
}

table.pretty thead th.sorting {
    background: #66A9BD url('images/sort_both.png') no-repeat right center;
}

The pagination control is slightly more complicated to style, but again still primarily about padding and colours. DataTables uses a number of classes to aid styling:

  • a.paginate_button - class given to elements used for pagination controls (i.e. each button)
  • a.paginate_active - class given to the element that shows which page we are currently on in the table (note that this will replace the paginate_button class).
  • a.paginate_button_disabled - class added to elements which will have no effect when clicked upon (for example the 'first' page when you are already on the first page).

Here we make the A elements act more like buttons by having them use display: inline-block and adding styles to make the cursor change into a hand when hovered over. Note also that a fixed width for the numbered buttons (div.dataTables_paginate span>a) is set in order to provide a consistent view and target for those buttons. Finally note that the information element (div.dataTables_info) needs a little extra top padding in order to align it correctly with the pagination buttons.

a.paginate_button,
a.paginate_active {
    display: inline-block;
    background-color: #608995;
    padding: 2px 6px;
    margin-left: 2px;
    cursor: pointer;
    *cursor: hand;
}

a.paginate_active {
    background-color: transparent;
    border: 1px solid black;
}

a.paginate_button_disabled {
    color: #3d6672;
}
.paging_full_numbers a:active {
    outline: none
}
.paging_full_numbers a:hover {
    text-decoration: none;
}

div.dataTables_paginate span>a {
    width: 15px;
    text-align: center;
}

div.dataTables_info {
    padding: 9px 6px 6px 6px;
}

Conclusion

We've seen in this post how a table can be styled to be attractive, distinctive and functional through the use of DataTables and some basic CSS. With the basic framework shown here, the styles can be easily modified to integrate smoothly with your web-site. Drop a message into the forum with some of the styles that you come up with!

I hope you've enjoyed this post! There is a thread in the forum for comments and discussion on this post.