Table basics and how to make them responsive

Ever since we left table based design in the early 2000s (or even later if you’re that kind of person), some well meaning developers might’ve gone overboard with the no-tables-at-all mentality, telling everyone they meet that tables are bad. Period.

Let’s get one thing straight — there is nothing wrong with using tables. At least not for tabular data, which is what the table element was created for. If, however, you try to still use it for layout, please go ahead and read this classical piece (also, this detailed answer on Stack Overflow is a great read) and then we calk talk again, ok?

Tabular data 101

A table element’s basic structure can be summarized accordingly (based on the article on the <table> element on Mozilla Developer Network):

  • an optional <caption> element
  • zero or more <colgroup> elements
  • an optional <thead> element
  • one of the two alternatives
    • one <tfoot> element, followed by
      • zero or more <tbody> elements
      • or one or more <tr> elements
    • a second alternative followed by an optional <tfoot> element
      • either zero or more <tbody> elements
      • or one or more <tr> elements

Basically, if we want a simple table with column headers that describe the contents of each column, we’d need something like this:

An optional summary of our table
Heading Heading Heading
Data Data Data

Note the scope attribute on the th element. This lets our user agent or any eventual assistive technology know that this table heading describes the entire column. Conversely, you can also set the scope to row, should your heading need to describe a row instead.

Heading Data Data

Note the simplified layout of this table. Since I didn’t have a need for column headings, I can just omit the thead element altogether and in such a case, the tbody element becomes superfluous as well. I chose to forego the captionas well, but it is recommended to provide a short summary, especially for assistive technologies that might benefit from it, since a well structured table with correct semantics allows the user to quickly get an overlook of the table without the need of having to go through the entire content of said table.

For some reason, it is valid to omit the scope attribute in HTML5. The W3 spec says:

The auto state makes the header cell apply to a set of cells selected based on context.

The scope attribute’s missing value default is the auto state.

“Based on context” feels a bit ambiguous to me, so my recommendation is to err on the side of thoroughness and specify your scope.

A quick word on styling

Forget everything about the old attributes align, bgcolor, cellpadding, cellspacing and so on. They are deprecated and should not be used. Any visual customisation should of course be done via CSS. For the sake of brevity, I’ll just provide you with a quick default stylesheet that I usually begin with, and you can then customise that to your liking.

table {
  width: 100%;
  border-collapse: collapse;
  border-spacing: 0;

td {
  border: 0;

td {
  vertical-align: top;
  padding: 0.25em 0.5em;

th {
  white-space: nowrap;

th {
  font-weight: bold;
  text-align: left;

tr:nth-child(even) {
  background: rgba(0,0,0,0.05);

Now we’ve got a borderless table with a nice zebra-row and table headings that won’t wrap.

Ok, that’s it for our crash course about tables!

Wide tables and mobile layouts

Tabular data can quickly grow and the rigid nature of tables will sooner or later cause your table to become very wide. When designing layouts for mobile devices where screen real estate is at a premium, we need to handle how our tables act.

Tables can’t break into several row, and the default behavior is to squeeze into its parent container, no matter how silly the result would look.

All we need is to wrap our table in a container.

Then we let the contents of this container scroll horizontally on overflow.

.scrollable-table {
  overflow-x: auto;

There we go! Now our table can be a lot wider than the screen it is viewed upon.

Going the extra mile

Mobile OS:es like iOS and more modern versions of OS X for Mac hide the scrollbar by default and this can pose a problem if the user has no idea the content of a table is scrollable. Adding a visual cue in the form of a nice radial gradient (acting like a drop shadow) might provide a clue that there is more content beyond the vertical fold.

.scrollable-table {
  overflow-x: auto;
  background: #fff no-repeat;
  background-image: radial-gradient(farthest-side at 100% 50%, #aaa, transparent);
  background-position: 100% 0;
  background-size: 1em 100%;
  border-right: 1px solid #ddd;

A slight caveat with this particular method is that the shadow will be visible even when the content is not necessarily scrollable. There’s a few ways we can deal with this, but we’ll save that one for a future post.

A complete example of all the above is available at Please feel free to fork it and experiment away.