HTML tables are here from the early days of the web. According to some sources, tables were part of HTML standard since version 3.2. It can be surprising that some web designers never worked with this element. In this article, we will discuss everything you need to know about tables. We will start with basic syntax and semantics. Then, we will try to make our tables responsive. Finally, we will talk about one myth some people, and clients, believe is true. So, let’s begin.



Basic syntax of HTML tables

Let’s start this article on a simple note. What are the absolutely necessary elements every HTML table has to have? You need table, tr and td elements. Table is, well it is the element that defines the table. Next, tr, allows you to define a single row inside the table. Finally, td defines a single cell in the row. So, on the top level will be table element. Inside it will be one or more tr. And, inside that will be one or more td. That’s it. This is the minimum markup you need to create a valid table.

HTML:

<!-- Simple table --> <table> <tr> <td>Cell one</td> <td>Cell two</td> <td>Cell three</td> </tr> </table>

Tables and semantics

What if you want to take it to another level? We all know that web is getting more and more oriented on semantic. It is not only about what you say, but also about how you say it. In other words, td is not the same as th, at least not for the browser. Sure, you can use some CSS to style these two elements so they look the same. However, browser will still know that these two elements are different, semantically. It is like h1 and p.

You can think about th as an analogy for h1 or other heading and tr as an analogy for p. Just like th, h1 adds more meaning and weight, if you want, to the text. Put simply, th is for header information. On the other hand, td is for plain data of the table. This is also why th is bold as default – it is more important. There is one thing I forgot to mention. You should always either fill the rows (tr) with the same number of cells (td) or use colspan attribute with specific number. Otherwise, the layout of table might not look like you want.

HTML:

<!-- Simple table with td and th --> <table> <tr> <th>Heading one</th> <th>Heading two</th> </tr> <tr> <td>Cell one</td> <td>Cell two</td> </tr> </table>

Grouping table content

However, this is not everything. Next, you can divide the table into smaller parts with thead, tbody and tfoot. None of these elements is necessary. They are only a “tool” you can use to group the content of the table in more meaningful way and reduce potential mess. You can think about these table elements as analogies to head, body and footer. Well, to a certain degree. If you decide to use these three elements, there are things you should remember.

All these elements have two things in common. First, they can’t be empty. If you decide to use any of these elements, it has to contain at least one row (tr). Otherwise, the table will not be valid. Also, these elements have to contain the same the same number of header (th) or data (td) table cells as the body of the table. Or, you can use the colspan attribute we already talked about above.

The second thing, these elements have in common, is that none of them will affect the layout of the table. As we discussed, when you use th instead td, browser will render the text as bold. Well, unless you use reset or normalize CSS stylesheet, or other custom styles to override the default styles. Reset stylesheet will make th look like td. Normalize CSS will keep th bold. The same is true for thead, tbody and tfoot. None of them will change how the table looks like in the browser.

The head and body

Since it is more likely that you will use thead and tbody, let’s talk about these first. The tbody element the best choice for grouping the “standard” content of the table. Meaning, you can basically take all rows (tr elements) with tds inside and put them inside tbody. Even if you do nothing else, this will be still valid table. Just like a piece of some text, HTML tables also don’t have to have a heading, or thead / th. It can be just a metaphorical pile of rows (tr) and cells (td).

HTML:

<!-- Simple table with tbody --> <table> <tbody> <tr> <td>Cell one</td> <td>Cell two</td> </tr> <tr> <td>Cell one</td> <td>Cell two</td> </tr> </tbody> </table>

Next is on the list is thead. Similarly to its sibling, thead element is also composed of one or more rows (tr). And, these rows can also contain standard table cells (td), along with table headings (th). You can use both types of cells, th and td, and your table will be perfectly valid. However, I don’t think it would be right to put td inside thead, in the terms of semantic. Chances are that if you want to use thead you want to add headings to columns. In that case, th makes more sense.

Otherwise, you could as well ditch the thead completely and put everything inside the tbody. Or, you could ditch both, thead and tbody. Still, this is just my personal opinion and preference. You can put td elements inside thead if you want. One more thing to remember. Thead element has to be before any tbody or tfoot element.

HTML:

<!-- Simple table with thead and tbody --> <table> <thead> <tr> <th>Th one</th> <th>Th two</th> </tr> </thead> <tbody> <tr> <td>Cell one</td> <td>Cell two</td> </tr> </tbody> </table>

Tables with “legs”

The last grouping element you can use in HTML tables is tfoot. Like the previous grouping elements, it should contain at least one table row (tr) with at least one table cell (td). No, unfortunately, there is no special type of table cell, like “tf”, dedicated only to tfoot. I think we already have enough of elements to work with. The question is, when to use this element? It is a good choice if you want to show some summary for each column of the table.

For example, if you have a table filled with numbers, you can use tfoot to show the totals of these numbers. Another way to use tfoot can be adding some footnotes to the table. Still, chances are quite high that you will not use this element very often. To this day, I can’t recall many situations when I used tfoot element. Usually, when I work with tables, I’m using only thead and tbody.

There is one thing in which tfoot is different from its siblings. This element must come after thead before tbody. This is not optional. So, if you use all three grouping elements in your HTML tables, the order is thead, tfoot and tbody. It is interesting that even that tfoot is before the tbody in the code, browser will render it after tbody. So, don’t worry that tfoot will break the layout of your table. Browser will render it in following order – thead, tbody and tfoot.

HTML:

<!-- Simple table with thead, tbody and tfoot --> <table> <thead> <tr> <th>Cost</th> </tr> </thead> <tfoot> <tr> <td>$470</td> </tr> </tfoot> <tbody> <tr> <td>$150</td> </tr> <tr> <td>$320</td> </tr> </tbody> </table>

Caption and grouping columns

There are three last table elements we should discuss as well. These are caption, colgroup and col. Caption, as you probably guessed, specifies the caption of the table. When it comes to caption, remember two things. First, it has to come right after the table tag. Second, you can use it only once for every table you have. It is like h1 heading, only one per article. Col and colgroup come together. The first must be nested inside the later.

You can use col and colgroup to style the entire columns instead of styling every cell in the column individually. Yes, the styles you set on col tags via style attribute will be applied to whole columns. One thing to remember is that col is self-closing tag, like img or input. It doesn’t have an end tag. The rules for using colgroup are simple. You can use it only as a first child (no caption) or right after caption. It has to come before thead, tbody or tfoot. And, col is the only valid child.

HTML:

<table> <caption>Personal data</caption> <colgroup> <col style="background-color: #aaa;"> <col style="background-color: #ccc;"> <col style="background-color: #eee"> </colgroup> <tr> <th>Name</th> <th>Surname</th> <th>Age</th> </tr> <tr> <td>Johny</td> <td>Clark</td> <td>33</td> </tr> </table>

Responsive web design and HTML tables

When web designers and developers talk about HTML tables, they often discuss one issue. HTML tables are not the best friends with responsive web design. Yes, tables can be quite a pain if you want to build responsive website or UI. The reason is simple. HTML tables are quite stubborn. They always take up as much space as their content needs. And, it doesn’t matter how wide or narrow the layout around the table is. Table will simply break it and overlap it.

For example, let’s say you have a website that contains one table. This table is composed of six columns with some random content. Let’s assume that the natural width of the table (fitting the content) is 700px. Then, when the layout gets narrower, the table will not “shrink” itself or become “scrollable”. It will overlap the layout as much as it needs to get those 700px. This is why web designer and developers like to sometimes replace tables with divs. Divs are more … Bendable?

Another interesting thing is that HTML tables is that they will never fill all remaining space on sides. In other words, if the table needs 700px it will take exactly 700px, not less and not more. So, if you want to have a table that spans across the whole width of the layout, you have to force it to do so. Otherwise, it will resize itself to the width its content needs. The question is, what if you want to use table and you need it to be responsive?

The solution for responsive HTML tables

The fastest and commonly used solution is simple. Instead of trying to somehow break the table with dozens of lines of CSS, you wrap it inside a div. Then, you add two lines of CSS. On the first line, set the overflow-x (horizontal) to “auto”. On the second line, set the max-width to “100%”. Thanks to this small tweak, the table will never overlap the wrapper div. Any time the div will be narrower than the table, horizontal scrollbar will appear. It will not let the table to overlap it.

HTML:

<!-- Relatively responsive table with horizontal scrolling --> <div class="table-wrapper"> <table> <thead> <tr> <th>Heading one</th> <th>Heading two</th> <th>Heading three</th> </tr> </thead> <tbody> <tr> <td>Col one</td> <td>Col two</td> <td>Col three</td> </tr> </tbody> </table> </div>

CSS:

.table-wrapper { overflow-x: auto; max-width: 100%; }

Scrollable tables and potential UX issues

Is this the most beautiful solution? No, not at all. In many browsers, the scrollbar may look even worse than table breaking (overlapping) the layout. Another issue is that part of the table is not visible without scrolling. This might not be such a problem if the table is small, if it has only few rows. However, imagine you have table with, say, 30 lines or even more. Since the scrollbar is under the table, user may not know that part of the table is hidden and she has to scroll.

In case like this one, adding a small note, about the fact the table is scrollable, above the table is a very good idea. As a designer, never assume user will somehow know the table might indeed be scrollable. And, never assume the user will try to scroll the table, just to make sure. People often want to do as much as they can with the least amount of effort, and thinking. If something is not visible, like scrollbar below the fold, they may not think it is there. And, they may not try to test it.

Smaller table on smaller screen

This brings me to another potential solution for making HTML tables responsive. You can use CSS to hide specific columns to make sure the table fits into the layout. You can see a demo of this technique here. Sounds good? Here is the catch. Your table has to have some “unnecessary” columns you can hide. Great. What if all columns are necessary? Then, you have two options. First, you can use previous scroll-based solution.

The second option to combine both approaches. Here is what I mean. First, you will wrap the table inside the div with that small CSS tweak. Next, you will hide some columns. Finally, you will add some button or switch so user can “toggle” those columns. As a result, when screen get too narrow, the table will become smaller by hiding some columns. No scrollbar will appear, unless the user clicks the button or switch. Then, columns will appear and table will be scrollable.

What is the difference between this and having only scrollable table? It increases the chance the user will notice that the table is scrollable. She will see the content move aside and this can make her wonder if there is more that’s hidden. In other words, she may try to scroll table. Or, she may scroll the page to see if there is a scrollbar. You can also place the button or switch under the table. So, when user clicks on it, and the scrollbar will appear, it will appear above the fold. She will see it.

Still, scrollable tables? Are you serious? Those scrollbars look like sh*t. I know and I share your pain and disgust. Fortunately, there are some CSS- and JavaScript-based ways to make scrollbars suck less. This is not bulletproof solution, but it can do the job.

Crushing the myths: HTML tables are valid

There is one myth many people, especially outside web design industry, believe to be true. In the last few months, some of my clients asked me if HTML tables are valid. In a fact, one client was actually afraid of using tables on his website. He really though that tables are no longer valid in HTML. It was quite a surprise to hear something like this. However, it makes it at least clear why the website used those pseudo-tables built with div elements and styled like tables.

Fortunately, it was quite fast and easy to explain my client that what he heard was a complete bullshit. HTML tables are as valid in HTML5 as they can. And, they will be valid in HTML5.1 as well. You can take a look at the HTML5.1 draft proposed by W3C. Then, you will see that all the elements we talked about in this article are here to stay, at least for a while. This includes elements such as table, caption, colgroup, col, tbody, thead, tfoot, tr, td and th.

As it seems, no new elements related to tables are coming. However, none of them are going away either. I have no idea where this myth about HTML tables being invalid originated. Take a look at the list of elements deprecated in HTML5. There is not a single mention of table element being deprecated. There are only attributes you could use on table elements that are no longer valid. These attributes like cellspacing, cellpadding, border, frame, bgcolor and so on.

Two things. The first thing is that these attribute are not completely gone. Instead, they were replaced with CSS, which is like ten times more flexible. So, don’t worry. You can still achieve the same effect. Second, who used these attributes anyway? Let me repeat this for one more time. HTML tables are valid in HTML5 and they will be valid in HTML5.1. So, if you have some data you want to show, you can use table. You don’t have to reinvent them with bunch of divs and CSS.

Closing thoughts on HTML tables

This is all I have for you for this article. We discussed the most important things related to HTML tables, from basic syntax, semantics and responsive design to the myths. There is a lot we didn’t talk about. Just like with other topics, there is always another layer to be explored and issues to be solved. Yet, I hope that this article gave you the material you need to start creating valid tables. Last words? Well, two. First, tables are valid. Second, don’t use tables for layout, only for data.

If you liked this article, please subscribe so you don't miss any future post.

Subscribe

If you'd like to support me and this blog, you can become a patron, or you can buy me a coffee 🙂

Become a Patron PayPal icon Donate via Paypal