Outline


Home

Creating HTML Tables


Styling

The simplest option for creating a table is to use the <table> element, but it is also possible to create a table with other elements and use flexbox or grid for the layout. Of course, libraries like Tabulator can do almost all the work for you if want really nice data tables with minimal effort.

Basic HTML Table

A simple table can be created from a skeleton like the below. You can separate the header rows from the rest of the table with the <thead>. Text for the cells is inputted inside of the <td> elements in the body and the <th> elements in the head.

<table>
    <thead>
        <tr>
            <th></th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td></td>
            <td></td>
        </tr>
    </tbody>
</table>

Flexbox Table

Using flexbox allows for a bit more flexibility in setting the width of each column. If you want the column widths to automatically flex, then you need to organize the table by columns rather than rows. This setup is a bit awkward, but it works well if you need responsive tables where different columns have different widths.

<div id="table">
    <div id="header">
        <div class="col">
            <span></span>
        	<div class="colBody">
                {% for i in range(1,header.length) %}
                <span>{{header[i]}}</span>
                {% endfor %}
            </div>
        </div>
    </div>
    <span id="body">
        {% for col in body %}
        <div class="col">
            <span>{{ col[0] }}</span>
            <div class="colBody">
                {% for i in range(1,col.length) %}
                <span>{{ col[i] }}</span>
                {% endfor %}
            </div>
        </div>
        {% endfor %}
    </span>
</div>

The #body element will need flex display with flex-direction as column. You can set the desired flex properties for each column to get the best set of widths.

Turning Data into a Table

Data Sources

If your data is already an array or json object, then you probably just need a few lines of JavaScript to convert it to the right format. Other common data sources include an API response, a CSV file, and a spreadsheet.

For an API call, the conversion will depend on the syntax of the response. Read the documentation to know the format of the array or object that gets returned.

To handle just about any CSV file, I use the papaparse module for Node. There are other options for Node or other frameworks, but you probably want to use an existing library unless you know the CSV is simple enough to split.

If you want a simple way to update the data regularly, then setting up the server to pull from a Google Sheets doc works well. The google-spreadsheet module is well-documented and makes this process straight-forward.

Once you have an array or object, you just need to insert into a template to create your table.

Nunjucks

On the server, I usually use the nunjucks templating system. If you create an object with head and body arrays, then the following template works well. You can adjust the syntax to meet your particular needs. If you only have one header row, you can eliminate the outer for loop in the <thead>.

This template can be copied into a full HTML file or imported for easy re-usability with multiple tables. Learn more about nunjucks at their website.

<table>
    <thead>
    {% for row in head %}
		<tr>{% for i in row %}<th>{{i}}</th>{% endfor %}</tr>
	{% endfor %}
    </thead>
    <tbody>
    {% for row in body %}
		<tr>{% for i in row %}<td>{{i}}</td>{% endfor %}</tr>
	{% endfor %}
    </tbody>
</table>

Mustache

On the browser, I usually use the mustache templating system. If you create an object with head and body arrays, then the following template works well. You can adjust the syntax to meet your particular needs. If you only have one header row, you can eliminate the outer for loop in the <thead>.

This template can be a string that mustache will render to HTML and then can be inserted into the DOM where needed. Learn more about mustache at their repository.

If the table data can be changed by users, then sanitize the output before adding to the HTML and be aware of any other security risks.


<table>
      <thead>
        {{#head}}
        <tr>{{#.}}<th>{{.}}</th>{{/.}}</tr>
        {{/head}}
      </thead>
      <tbody>
        {{#body}}
        <tr>{{#.}}<td>{{.}}</td>{{/.}}</tr>
        {{/body}}
      </tbody>
</table>

Features

Sorting

If the table is small enough that the client receives all the rows, then you likely want to sort client-side. If you are already doing client-side rendering then it is simple to sort the object and render the updated table. If the table is served as a static table then you either need to send the client an object with the data or parse it from the DOM.

This repl has simple example code for sorting a table somewhat normally, but it is possible to sort without any JavaScript if that is something you really want to do. Read my blog post here for more information.

Pagination

Pagination tends to be very simple if no server calls are required. You can render the entire table and just display some rows (easy to do with just CSS) or you can render a new table when the page changes. Either way this process should be basically instantaneous for any reasonably sized table.

This repl paginates with JavaScript and this repl paginates with CSS.

Filtering

There are lots of filters that are trivial to implement. Simple comparisons of either strings or numbers will be fast and only need a few lines of code. More complex filters are certainly possible but may require lengthier code.

Read my blog post here for more information on filtering with pure CSS. This repl filters with JavaScript.

Examples

If you want to see what types of tables are possible with just HTML and CSS, go to csshole.com for sortable tables about Wikipedia pageviews by country, paginated tables about near Earth objects, or filterable tables about postfixed expressions.