Skip to main content
Guide Collection

A Complete Guide to the Table Element

The <table> element in HTML is used for displaying tabular data. You can think of it as a way to describe and display data that would make sense in spreadsheet software. Essentially: columns and rows. In this article we’re going to look at how to use them, when to use them, and everything else you […]

Monthly Sponsor
Thanks, Keen!

The <table> element in HTML is used for displaying tabular data. You can think of it as a way to describe and display data that would make sense in spreadsheet software. Essentially: columns and rows. In this article we're going to look at how to use them, when to use them, and everything else you need to know.

A Very Basic Example

Here's a very simple demo of tabular data:

See the Pen xkrGs by Chris Coyier (@chriscoyier) on CodePen

It is data that is useful across multiple axis. Imagine running your finger across a row (horizontal) to see a single person and relevant information about them. Or up and down a column (vertical) to get a sense of the variety or pattern of data on that point.

Head and Body

One thing we didn't do in the very basic example above is semantically indicate that the first row was the header of the table. We probably should have. That entire first row contains no data, it is simply the titles of columns. We can do that with the <thead> element, which would wrap the first <tr> (it could wrap as many rows as needed that are all header information).

That HTML would be like this:

See the Pen tzjid by Chris Coyier (@chriscoyier) on CodePen

When you use <thead>, there must be no <tr> that is a direct child of <table>. All rows must be within either the <thead>, <tbody>, or <tfoot>. Notice that we also wrapped all the rows of data in <tbody> here.


Along with <thead> and <tbody> there is <tfoot> for wrapping table rows that indicate the footer of the table. Like <thead>, best for semantically indicating these are not data rows but ancillary information.

What is unique about <tfoot> is the placement in the HTML. It comes after <thead> and before <tbody>! You might think it would be the last thing before the end of <table>, but not so in this case. I believe this is an accessibility concern, as the footer may contain information necessary to understand the table, it should be before the data in the source order.

Despite coming first in the source order, <tfoot> does indeed render at the bottom of the table, making it a rather unusual HTML element.

It can be used, for example, to repeat the header in the case of a visually very tall/long table where it may be easier to see the column titles at the bottom than the top. Although you don't necessarily need to use it that way.

See the Pen mIjil by Chris Coyier (@chriscoyier) on CodePen

<tfoot> is just begging for clever tricks with layout where the position of elements jumps around from bottom to top depending on needs. For instance a nav bar along the bottom of a screen, but with the HTML source toward the beginning where navigation should be.

The Cells: td and th

The individual cells of a table are always one of two elements: <td> or <th>. You can put whatever you want inside a table cell, but these are the elements that make them a table cell. <th> elements are "tabular headers" and <td> elements are "tabular data".

Using our existing simple demo, the top row is all headers. Not data, just titles for the data. All the rest of the rows are data. So:

See the Pen npvAf by Chris Coyier (@chriscoyier) on CodePen

<th> elements are not necessarily limited to being within the <thead>. They simply indicate header information. So they could be used, for instance, at the start of a row in the <tbody>, if that was relevant. We'll cover a case like that later.

Basic Styling

Most tables you will ever see use colors and lines to distinguish different parts of the table. Borders are very common. By default, all table cells are spacing out from one another by 2px (via the user-agent stylesheet), like this:

See the Pen GmsEc by Chris Coyier (@chriscoyier) on CodePen

Notice the slight extra gap between the first row and the rest. That is caused by the default border-spacing being applied to the <thead> and <tbody> pushing them apart a bit extra. This isn't margins, they don't collapse. You can control that spacing like:

table {
  border-spacing: 0.5rem;

But far more common is to remove that space. That property is completely ignored and the space collapsed if you do:

table {
  border-collapse: collapse;

Just a little padding, borders, and making those <th> elements be left-aligned goes a long way to make for a simple, styled table:

See the Pen kaErt by Chris Coyier (@chriscoyier) on CodePen

Connecting Cells

There are two important attributes that can go on any table cell element (<th> or <td>): colspan and rowspan. They accept any positive integer 2 or larger. If a td has a colspan of 2 (i.e. <td colspan="2">) it will still be a single cell, but it will take up the space of two cells in a row horizontally. Likewise with rowspan, but vertically.

See the Pen fixJg by Chris Coyier (@chriscoyier) on CodePen

You'll have to do a bit of mental math everything you start working with connected cells. Colspan is fairly easy. Any table cell is "worth" one, unless it has a colspan attribute and then it's worth that many. Add up the values for each table cell in that table row to get the final value. Each row should have exactly that value, or else you'll get an awkward table layout that doesn't make a rectangle (the longest row will stick out).

Rowspan is similar, it's just a little harder and more of a mental leap, because columns aren't grouped like rows are. If a table element has a rowspan attribute, it spans across two rows vertically. That means the row below it gets +1 to it's table cell count, and needs one less table cell to complete the row.

It can be awkward to work out in your head, but we're developers here, we can do it =).

Often these attributes are used in really simple ways like connecting a few related table headers:

See the Pen AlxGt by Chris Coyier (@chriscoyier) on CodePen

As Wide As They Need To Be... Or fill the container... Or beyond

The table element itself is unusual in how wide it is. It behaves like a block-level element (e.g. <div>) in that if you put one table after another, each will break down onto its own line. But the actual width of the table is only as wide as it needs to be.

See the Pen JnLIt by Chris Coyier (@chriscoyier) on CodePen

If the amount of text in the tables widest row only happens to be 100px wide, the table will be 100px wide. If the amount of text (if put on one line) would be wider than the container, it will wrap.

However if text is told to not wrap (i.e. white-space: nowrap;) the table is happy to bust out of the container and go wider. Table cells will also not wrap, so if there are too many to fit, the table will also go wider.

See the Pen ILrKi by Chris Coyier (@chriscoyier) on CodePen

Two Axis Tables

Sometimes it makes sense for tabular data to have two axes. Like a cross-reference situation. A multiplication table is an example of this:

See the Pen Multipication Table by Chris Coyier (@chriscoyier) on CodePen

I might skip a <thead> in this situation even though that first row is all header. It's just no more important than the vertical column of headers so it feels weird to group that top row alone. Just make on row of all <th> and then each subsequent row with the first cell only as <th>.

When To Use Tables

It's a good time to take a break and discuss the when of tables. Perhaps you've heard the generic advice: tables are for tabular data (see the first sentence of this blog post). The "would this make sense in a spreadsheet?" test is usually appropriate.

What kinds of things are appropriate in tables? Here are some: a plan/pricing/features comparison, bowling scores, an internal grid of employee data, financial data, a calendar, the nutrition facts information panel, a logic puzzle solver, etc.

You might occasionally hear: tables are unsemantic. That's not true - they semantically indicate tabular data. Tables are the right choice when that is the case.

When NOT To Use Tables

An inappropriate use for tables is for layout. That may seem counter-intuitive. At a glance at how tables work may make them seem ideal for layout. Easy to control, extremely logical, predictable, and not-at-all fragile.

There are some significant problems with using tables for layout though. First, HTML tags mean things. As we covered, table elements semantically describe tabular data. Using them for anything else is a breach of semantic duty. You aren't going to get a fine in the mail, but you aren't getting as much value from your HTML as you could.

Talking about semantics is a little difficult sometimes (some reads: 1, 2, 3, 4, 5), so let's talk about something we all generally agree on (even if we aren't as good as it as we want to be): websites should be accessible. One part of accessibility is screen readers. Screen readers read tables from top to bottom, left to right. That means the order of how your site is presented is dictated by the table structure, which is dictated by visual choices not accessibility choices. Not to mention a screen reader may even announce the start of tabular data which would be worse than useless.

Speaking of source order, that affects more than accessibility. Imagine a "sidebar on the left" layout. A table would dictate that table comes first in the source order, which while also being bad for accessibility, is likely bad for SEO as well, potentially valuing your ancillary content above primary content.

Could you fix the SEO issues by using semantic tags within the table tags? Possibly somewhat, but now you're using double the HTML. If you really need the layout abilities of a table but want to use semantic tags, see the next section. If you are somehow absolutely stuck using table tags for layout, use the ARIA role="presentation" on the table to indicate it as such.

As I write this in the latter half of 2013, tables have become far less prevalent and even appealing as a layout choice. We're seeing a lot more use of fixed and absolute positioning which you cannot do inside a table. We're seeing flexbox being awesome and being right on the edge of mainstream usability. We're seeing grid layout starting to grow up. We're seeing inline-block be used powerfully. We're seeing the fragility of floats in the olden days fade away.

Rarely do you see modern websites touch tables for layout. The last holdout is HTML emails. The landscape of what renders emails is super wide. It is everything we deal with on the web, plus the world of native apps on both mobile and desktop on operating systems new and ancient. You can do some progressive enhancement for emails, but the layout itself is still generally regarded as being safest done in tables. That is substantiated by the fact that the major email sending services still all offer templates as tables.

Making Semantic Elements Behave Like a Table

CSS has properties to make any element you wish behave as if it was a table element. You'll need to structure them essentially as you would a table, and it will be subject to the same source-order-dependency as a table, but you can do it. I'm not crapping on it either, it's genuinely useful sometimes. If that layout style solves a problem and has no negative order implications, use it.

Don't use inline styles, but just for understanding here's how that would go:

<section style="display: table;">
  <header style="display: table-row;">
    <div style="display: table-cell;"></div>
    <div style="display: table-cell;"></div>
    <div style="display: table-cell;"></div>
  <div style="display: table-row;">
    <div style="display: table-cell;"></div>
    <div style="display: table-cell;"></div>
    <div style="display: table-cell;"></div>

A handy trick here is that you don't even need the table-row element in there if you don't want. A bunch of display: table-cell; elements that are children of a display: table; element will behave like they are all in one row.

You always alter the display property of the element to get the table-style behavior. Here's the values:

display: table                /* <table>     */
display: table-cell           /* <td>        */
display: table-row            /* <tr>        */
display: table-column         /* <col>       */
display: table-column-group   /* <colgroup>  */
display: table-footer-group   /* <tfoot>     */
display: table-header-group   /* <thead>     */

Notice there is no <th> alternative. That is for semantic value only. It otherwise behaves just like a <td>, so, no need to replicate it in CSS.

There is also display: inline-table; which is pretty interesting. Remember we talked about how weird table elements widths are above. They are only as wide as they need to be, yet break onto new lines. It's almost like they are inline-block elements which happen to break. This makes them literally like inline-block elements, without the breaking.

If you want to learn a lot more about using semantic elements but also table-style layout, check out the book Everything You Know About CSS Is Wrong!

I've never been a huge fan of that title as it suggests that using this table style layout is the right way and any other layout technique you use is the wrong way. But as I've said, this can be tremendously useful and I'm glad it's in CSS. Just be acutely aware that no matter what kind of elements you use to create a table-based layout, it still subject to the same problems (largely source order dependency).

All Table Related Elements

There is a few elements above we haven't touched on yet. Let's look at all the HTML table related elements. You know what, we might as well use a table to do it:

Element What it is
<table> The table itself
<caption> The caption for the table. Like a figcaption to a figure.
<thead> The table header
<tbody> The table body
<tfoot> The table footer
<tr> A table row
<th> A table cell that is a header
<td> A table cell that is data
<col> A column (a no-content element)
<colgroup> A group of columns

All Table Related Attributes

There are suprisingly few attributes that are specific to tables. Of course you can use class and ID and all the typical global attributes. There used to be quite a few, but most of them were specific to styling and thus deprecated (as that is CSS's job).

Attribute Element(s) Found On What it does
colspan th, td extends a cell to be as wide as 2 or more cells
rowspan th, td extends a cell to be as tall as 2 or more cells
span col Makes the column apply to more to 2 or more columns
sortable table Indicates the table should allow sorting
headers td space-separated string corresponding to ID's of the <th> elements relevant to the data
scope th row | col | rowgroup | colgroup (default) - essentially specifies the axis of the header. The default is that a header is heading a column, which is typical, but a row might start with a header also, where you would scope that header to the row or rowgroup.

Deprecated Attributes

Don't use any of these. The are deprecated. While they may work in some browsers today, there is a chance they stop working in the future.

Deprecated Attribute What to use instead
align Use float property instead
valign Use vertical-align property instead
char The correct answer is to use text-align: "x"; where x is the character to align on, but it's not implemented anywhere yet. But this attribute isn't supported either, so no big loss.
charoff See above
bgcolor Use background property instead
abbr "consider starting the cell content by an independent abbreviated content itself or use the abbreviated content as the cell content and use the long content as the description of the cell by putting it in the title attribute"
axis Use the scope attribute instead
border Use border property instead
cellpadding Using padding property instead
cellspacing Use border-spacing property instead
frame Use border property instead
rules User border property instead
summary Use <caption> element instead
width Use width property instead

The Table Stack

There is an implied vertical stacking of table elements, just like there is in any HTML parent > descendent scenario. It is important to understand in tables because it can be particularly tempting to apply things like backgrounds to the table itself or table rows, only to have the background on a table cell "override" it (it is actually just sitting on top).

Here's how that looks (using Firefox 3D feature in its dev tools):

Important Style Rules for Tables

You can use most CSS properties on table elements. font-family works on tables just like it does on any other element, for example. And the rules of cascade apply. Apply font-family to the table, but a different font-family on the table cell, the table cell wins because that is the actual element with the text inside.

These properties are either unique to table elements or they behave uniquely on table elements.

CSS Property Possible values What it does
vertical-align baseline
Aligns the content inside a cell. Works particularly well in tables, although only the top/bottom/middle make much sense in that context.
white-space normal
Controls how text wraps in a cell. Some data may need to be all on one line to make sense.
border-collapse collapse
Applied to the table to determine if borders collapse into themselves (sort of like margin collapsing only bi-directional) or not. What if two borders that collapse into each other have conflicting styles (like color)? The styles applied to these types of elements will "win", in order of "strength": cell, row, row group, column, column group, table.
border-spacing length If border-collapse is separate, you can specify how far cells should be spaced out from each other. Modern version of cellspacing attribute. And speaking of that, padding is the modern version of the cellpadding attribute.
width length Width works on table cells just about how you would think it does, except when there is some kind of conflict. For instance if you tell the table itself to be 400px wide then the first cell of a three-cell row to be 100px wide and leave the others alone, that first cell will be 100px wide and the other two will split up the remaining space. But if you tell all three of them to be 10000px wide, the table will still be 400px and it will just give each of them a third of the space. That's assuming white-space or elements like an image don't come into play. This is probably a whole post in itself!
border length Border works on any of the table elements and just about how you would expect. The quirks come in when you collapse the borders. In this case all table cells will have only one border width between them, rather than the two you would expect them to have (border-right on the first cell and border-left on the next cell). In order to remove a border in a collapsed environment, both cells need to "agree" to remove it. Like td:nth-child(2) { border-right: 0; } td:nth-child(3) { border-left: 0; } Otherwise, source order/specificity wins which border is shown on which edge.
table-layout auto
auto is the default. The width of the table and its cells depends on the content inside. If you change this to fixed, the table and column widths are set by the widths of table and col elements or by the width of the first row of cells. Cells in subsequent rows do not affect column widths, which can speed up rendering. If content in subsequent cells can't fit, the overflow property determines what happens.

This list isn't exhaustive. There are other CSS quirks that are relevant to tables. For instance, you can't relatively position a table cell in which to either nudge it around or absolutely position things within it. There are ways though.

If you can think of more CSS weirdness with tables, share in the comments below.

Default Styles / User Agent Stylesheet

WebKit does this:

table {
    display: table;
    border-collapse: separate;
    border-spacing: 2px;
    border-color: gray

thead {
    display: table-header-group;
    vertical-align: middle;
    border-color: inherit

tbody {
    display: table-row-group;
    vertical-align: middle;
    border-color: inherit

tfoot {
    display: table-footer-group;
    vertical-align: middle;
    border-color: inherit

table > tr {
    vertical-align: middle;

col {
    display: table-column

colgroup {
    display: table-column-group

tr {
    display: table-row;
    vertical-align: inherit;
    border-color: inherit

td, th {
    display: table-cell;
    vertical-align: inherit

th {
    font-weight: bold

caption {
    display: table-caption;
    text-align: -webkit-center

I inspected each element in Chrome Dev Tools too, which is now on Blink, and it's still the same.

It's funny though. For sure, the text in <th>s is centered (text-align: center;) by default. But that's not in the UA stylesheet. Not a huge deal but rather mysterious and makes you wonder what other mysterious things happen in rendering.

The UA stylesheet for tables differs from browser to browser. For example, in Firefox (here's 3.6's UA Stylesheet, but this is true in v23 too) table cells have this:

td { 
  display: table-cell;
  vertical-align: inherit;
  text-align: inherit; 
  padding: 1px;

Most notably, 1px of padding that WebKit doesn't have. Not a huge deal in most cases, surely, but it is different. That's what CSS resets (and related projects) are all about: removing the differences. So let's check those out.

Resetting Default Table Styles

The most popular CSS reset in the world, the Meyer Reset, does this to tables:

table, caption, tbody, tfoot, thead, tr, th, td {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
table {
  border-collapse: collapse;
  border-spacing: 0;

It's done the same way in the HTML5 Reset and the HTML5 (Doctor) Reset Stylesheet.

There is an alternative to CSS resets though, Normalize.css. The philosophy is slightly different. Rather than zero out all styles, it specifically sets known-to-be inconsistent styles to a reasonable default. My general advice on using Normalize.css is: don't remove anything from it. If it's in there, it needs to be for consistency. But feel free to change anything in there.

Normalize only does this to tables:

table {
  border-collapse: collapse;
  border-spacing: 0;

I'll have to dig into the reasoning here a little deeper because it seems unusual...

  1. I'm a fan of border-collapse: collapse because spacing between cells is usually way awkward, but, the default in every browser I know of is border-collapse: separate; so isn't in need of normalization.
  2. If border-collapse is collapse, border-spacing doesn't matter.
  3. Table cell elements are in need of normalization (e.g. Firefox padding difference) but that isn't there.

Not a hugely big deal.

This is the kind of thing I would probably normally do:

table {
  border-collapse: collapse;
  width: 100%;
th, td {
  padding: 0.25rem;
  text-align: left;
  border: 1px solid #ccc;

"Implied" Elements and Unclosed Tags

Check out this rather awkward bit of HTML:


This may be weird to look at, but it's valid. What's going on here?

  • The <col> tag is just one of those no-content elements that doesn't ever need a closing tag. Like <br> / <br />
  • The <td> element doesn't need to be closed in certain circumstances: "The end tag may be omitted, if it is immediately followed by a <th> or <td> element or if there are no more data in its parent element."
  • The missing closing </tr> tag is the same story: "The end tag may be omitted if the <tr> element is immediately followed by a <tr> element, or if the parent table group (<thead>, <tbody> or <tfoot>) element doesn't have any more content."

If we inspect the rendered table in the browser, we can see that the tags that were missing their closing tags are shown with closing tags. Those are automatically added for us. But there are also some brand new elements in there:

One thing to notice is the <col> is wrapped within a <colgroup> automatically. Even if we were to do:



colgroup:first-child {
  background: red;

You would think the second cell would be red, not the first, because the "first" colgroup only affects the second cell. But when rendered, both of those columns get wrapped in a colgroup, so the CSS selector will select the first one.

The <tbody> element is also implied. If you don't use any of tbody, thead, or tfoot, the whole guts of the table will be wrapped in tbody. If you use a thead, the whole table will be wrapped in that until it find a tbody, then it will auto-close the thead if you don't, and wrap the rest in tbody (also optional to close). If if finds a tfoot, you can imagine what happens (although remember tfoot should come before tbody).

You can actually use these elements in CSS selectors even though you didn't put them in your actual HTML. I probably wouldn't advise it just because that's weird, confusing, and styling tag selectors usually isn't advisable anyway.

Making a Table Not a Table

A situation may arise someday where you need to force a table element to not exhibit its table-style layout behavior and behave more like a regular element.

The trick is essentially to reset the display property of the table cells:

th, td {
  display: inline;

We can pretty quickly un-table a table:

See the Pen Untabling by Chris Coyier (@chriscoyier) on CodePen

Just to be safe, I'd reset the whole she-bang. Just makes me feel better knowing parent elements are also along for the ride and won't get freaky.

table, thead, tbody, tfoot, tr, td, th, caption {
  display: block;

This is primarily useful in responsive design where the traditional table layout makes sense on large screens but needs significant shifts to make sense on smaller screens. There is a whole section on that below.

Table Accessibility

We already talked about the problems with using tables for layout and accessibility. But assuming table is being correctly used for tabular data, there are still quite a few accessibility concerns.

There are some great articles on this out there:

Zebra Striping Tables

If you don't set a background-color on the table cell elements, you can set them on the table rows themselves. So at the most basic, you can do:

tbody tr:nth-child(odd) {
  background: #eee;

We're using the tbody in the selector because it's unlikely you'd want to stripe header and footer rows. Set the even rows as well if you want to be specific about it instead of let what is underneath show through.

If you need to support browsers that don't understand :nth-child() (pretty damn old) you could use jQuery to do it.

See the Pen Zebra Striped Table by Chris Coyier (@chriscoyier) on CodePen

Studies seem to show that zebra stripping in generally a good idea.

Highlighting Rows and Columns

Hightlighting a particluar row is fairly easy. You could add a class name to a row specifically for that:

<tr class="highlight">

See the Pen Zebra Striped Table by Chris Coyier (@chriscoyier) on CodePen

Highlighting a column is a bit trickier. One possibility is to use the <col> element, which does allow us to set styles for cells that appear in that column. It's weird to wrap your head around, because the cells that are affected by <col> aren't actually descendants of it. The browser just kinda knows what you mean.

A table with four columns in each row would have four <col> elements:




Then you could highlight a particular one, like:

col:nth-child(3) {
  background: yellow; 

See the Pen Zebra Striped Table by Chris Coyier (@chriscoyier) on CodePen

However this is rarely useful. If you set the background of a row element or table cell element, that will always beat a background of a column element. Regardless of specificity.

You're probably better off setting a class name on each individual table cell element that happens to match that column position in the row. Like:

  background: yellow;

Highlighting Column/Row/Cell on Hover

Cell highlighting is very easy. You can do it right in CSS:

td:hover { /* th:hover also if you wish */
  background: yellow;

Row highlighting is just as easy. You can set the background on table rows and it will show as long as you don't set a background on the table cells.

tbody tr:hover {
  background: yellow;

See the Pen Zebra Striped Table by Chris Coyier (@chriscoyier) on CodePen

If you do set a background on the table cells, you can always just to tr:hover td, tr:hover th { } so still pretty easy.

Column highlighting is tricker. You can't use col:hover because those columns aren't actual elements that take up pixel space on the screen that you could hover over. The only option is JavaScript.

I wrote it up in Vanilla JavaScript here, just for fun:

See the Pen Column Highlighting in Vanilla JavaScript by Chris Coyier (@chriscoyier) on CodePen

It works like this:

  1. Get a collection of all cells
  2. Bind a mouseover and mouseout event to all those cells
  3. When the mouseover event fires, get the position in the row of that cell
  4. Loop through all rows and add a highlighting class to each cell in that row that matches that position
  5. When the mouseout event fires, remove the highlighting class from all cells

And here I've combined both row and column highlighting. I used jQuery to make it all 12 lines of code (the raw JavaScript was getting pretty exhausting).

See the Pen Row & Column Highlighting in jQuery by Chris Coyier (@chriscoyier) on CodePen

It's the same concept, it's just much easier to make element collections, and find and select by indexes in jQuery.

Nicely Styled Tables

Some depth, visually distinct headers, and a terminal matching the header.

See the Pen IyDpa by Phelipe M. Peres (@mestremind) on CodePen

When the table is hovered, only the current row highlighted stays dark text, the others fade back. Also note on this one: the roundered corners on the table itself are only possible while you have border-collapse: separate;

See the Pen Crisp table by JOAQUIN RAPHAEL ARCAJO (@jrarcajo) on CodePen

Here's another where the non-hovered rows literally blur:

See the Pen Fade and Blur on Hover Data Table by Jack Rugile (@jackrugile) on CodePen

Twitter Bootstrap has very minimal table styling:

See the Pen KnJfk by Chris Coyier (@chriscoyier) on CodePen

This one, as a bonus, has keyboard control!

See the Pen HeavyTable by Victor Darras (@victordarras) on CodePen

I'm trying to keep a collection of well-designed tables for reference. So if you have any good ones, let me know. Hong Kiat also has a blog post collection.

Table Search

Where table sorting can be quite complicated, table search can be quite easy. Add a search input, and if the value in there matches text anywhere in a row, show it, and hide the others. With jQuery that might be as easy as:

var allRows = $("tr");
$("input#search").on("keydown keyup", function() {
  $("tr:contains('" + $(this).val() + "')").show();

Here's a take with RegExp instead:

See the Pen Quick Table Search by Alexander Standke (@XanderStrike) on CodePen

And here's on in raw JavaScript:

See the Pen Light Javascript Table Filter by Chris Coyier (@chriscoyier) on CodePen

Tables Can Be Difficult in Fluid/Responsive Designs

I've written about this in the past, and I think this graphic kind of sums up the experience of a data table on a small screen:

I ultimately created a roundup once a variety of interesting solutions came around.

Real quick though:

Here's a couple of styled live demos with different takes:

See the Pen Responsive Table by Geoff Yuen (@geoffyuen) on CodePen

See the Pen A responsive table by Israel Lemus (@izzrael) on CodePen

Fixed Header Tables

This is another thing I've written about in the past as well as done a little screencast. Those are fairly old, but the demo still works.

The most modern way of handling fixed headers is position: sticky; Here's an article on that. I'm honestly not quite sure the recommended way to use it with tables though. It doesn't work on <thead> under normal circumstances. That kinda makes sense because you can't absolutely position table innards. But it does work on <th>. Anyway if someone wants to figure that out, that'd be a good update to this article (or something).

Here's a live demo of a jQuery plugin that does the trick. I'd probably go for something like this these days until sticky shakes out more.

See the Pen Table with fixed header on scroll by jgx (@jgx) on CodePen

Using Emmet for Creating Table Markup

Emmet is a great tool for a bunch of reasons. One of which is writing HTML abbreviations and having them expand out into real HTML. Since tables are so repetitive and verbose, Emmet is perfect for them. Emmet works on CodePen too =)

Simple four rows and four columns


Five rows with the header on the left


A row of headers on the top


Employees with incrementing IDs

table>tr>th{Name}+th{ID}+th{Favorite Color}^tr*3>td{Name}+td{$$$$$}+td{Blue}

Table with header, footer, and content


Same but with cell content in each cell

table>thead>tr>th{Header Cell}*5^^tfoot>tr>th{Footer Cell}*5^^tbody>tr*10>th{Row Header}+td{Cell Data}*4

JavaScript Generated Tables

JavaScript provides some very specific methods for dealing with tables through the HTMLTableElement API. Louis Lazaris wrote a little about it recently. You can use it to create tables with JavaScript, access sub-elements, and change properties in very specific ways. Here's the MDN page with the scoop.

Here's that at work:

See the Pen inosC by Chris Coyier (@chriscoyier) on CodePen

Table Sorting

Imagine a table with two columns. One for Employee ID's and another for Employee Email Address. There are headers for each column. It would be handy to be able to click those headers and sort the table by the data inside. For instance, numerical order, alternating between ascending and descending, for the ID's and alphabetical for the email addresses. That's what table sorting is all about. Making the data more useful.

This is such a common and generic need, that there is actually specification ready for it. Just put the sortable attribute on the table and it will automatically do it as long as you follow a couple of rules laid out in the spec.

At the time of this writing, I don't know of any browsers supporting table sorting natively. But there are lots of third-party options!

  • tablesorter - jQuery-based "Flexible client-side table sorting"
  • sorttable - raw javaScript
  • tablesort - "a small & simple sorting component for tables. Written in Javascript and dependency free"

What's with table sorting scripts and lowercase? Anyway, here's a demo of tablesorter:

See the Pen Table Exercise by egon0119 (@egon0119) on CodePen

If those don't do it for you, Codrops rounded up 33 different table sorting scripts, so there are plenty to choose from.

And those are all JavaScript solutions. It's certainly possible to sort data on the back-end and display the table already sorted in the HTML. That might be required in the case of paginated tables where all the data isn't available right in the DOM.

More Information


  1. User Avatar
    Russell Heimlich
    Permalink to comment#

    <tfoot> comes before <tbody> so ‘user-agents can render the footer before the numerous rows of data’ per the spec via

    • User Avatar
      Russell Heimlich
      Permalink to comment#

      Oops. Jumped the gun. I think the other reason is for printing of tables. With the <tfoot> before all of the data the browser can use it to render the table foot when the table is broken up by a page break. If the <tfoot> comes last, the browser can’t look ahead to see if the <tfoot> is even used.

    • User Avatar
      Permalink to comment#

      In reply to your second comment: yes, while printing a very long table with informations from tfoot repeated and printed on each page, it could take 50 pages and tons of tbody code to have printed and parsed (on a Pentium or 68040 processor with a few MB of RAM back in the nineties).

      Having as soon as possible all the information to be repeated allows user agents to print the first page before having processed the remaining 49 pages…

    • User Avatar
      Permalink to comment#

      Thanks! The best article for tables!

    • User Avatar
      uae sharjah
      Permalink to comment#

      That is weird this crashes my Dreamweaver! Are you using the new CS6 or the older versions? I think I need a just before the closing of

    • User Avatar
      Ali Mihandoost
      Permalink to comment#

      Yes, Its true.

    • User Avatar
      Permalink to comment#

      nice table overview, but you forgot to mention table-layout: auto and fixed, auto being the default which lets cells expand nicely, however occasionally you will need to have fixed width columns and once you enter into the world of table-layout: fixed you will need to set explicit widths for each cell or column which can quickly become a pain.

    • User Avatar
      Permalink to comment#

      Good article on how versatile you can be with CSS and making tables pretty.

  2. User Avatar
    Tyler Shuster
    Permalink to comment#

    Wonderful writeup, as always. One question on semantics, though. On sites like The Verge, there are usually grids of articles laid out in a very table-like style. While you say that tables should only be used for tabular data, I argue that layout like this is in fact tabular data. The convention rarely appears outside of blog homepages, but it does in fact perform the original function of a table: to lay out value in a visually-organized manner.

    My only reason to use tables in this manner would be for the row/columnspan functionality, given the debatable semantics. Is there an easy way to duplicate this without using tables?

    • User Avatar
      Russell Heimlich
      Permalink to comment#

      You could use display:table, table-row, table-cell, flex-box, absolute positioning like what The Verge is doing, or you could even hack it with floats. Each method has it’s own pros and cons. If you were doing it with table markup you would run into troubles making it be responsive and collapse into a less columns.

    • User Avatar
      Chris Coyier
      Permalink to comment#

      I argue that layout like this is in fact tabular data

      I would say a group of articles is definitely not tabular data. That’s a good candidate for using display: table and its buddies to replicate table-like layout without having to use actual tables.

    • User Avatar
      Permalink to comment#

      It isn’t tabular data, really. The grid layout is a stylistic choice and can be read as a table-like grid, or as a single column, or arrayed around a single focus.

      If you want to replicate a tabular look that is pure style, use styles.

  3. User Avatar
    Permalink to comment#

    This is deep! The best article I’ve seen on this.

    • User Avatar
      Permalink to comment#

      I agree

    • User Avatar
      Permalink to comment#

      Here here. Quite detailed. This should be linked to from HTML5Doctors diagnosis for <table>. Thank you, Chris for lending validation to the use of table styles on non-table elements. Stop griping about table styles, folks. They serve a very good and unique purpose.

    • User Avatar
      C R
      Permalink to comment#

      Agreed also!
      Excellent article and I’m saving this as a reference for future work.
      Thanks so much!

  4. User Avatar
    Permalink to comment#

    Thanx for the nice and comprehensive write-up!

  5. User Avatar
    Permalink to comment#

    Making a Table Not a Table

    Alas IE9 couldn’t care less the way you want to deconstruct a table with CSS like
    table, thead, tbody, tfood, tr, td, th, caption { display: block }
    AFAIK it works everywhere else but not in IE9… Well, everywhere else as long as you include tbody { display: block } even if you’ve no tbody element in your code! Browsers will add a shadow tbody and it’ll be styled by default as any tbody would be.

    Safari 6 and total width of a table

    Browsers will adapt to a lot of things when it comes to table, with table-layout: fixed algorithm of rendering as well as with table-layout: auto algorithm: conflicting width values or even lack of cells in some rows (quite amazing imo)!

    Most browsers will let you set widths on each header cells in header (thead > tr > th) and a width on parent table that is not equal to the total width of its columns. Along with table-layout: fixed, it’ll adapt somehow the widths of individual columns in a reasonable manner.

    But be sure to test on Safari 6 as this one won’t behave like others and may render larger tables than you’d expect after testing in Fx, Chr and E6-10. You need a Mac or a testing service as Safari 6 is only present on OS X.

  6. User Avatar
    Trevor Hungerford
    Permalink to comment#


    • User Avatar
      Corey Bruyere
      Permalink to comment#

      I agree.

    • User Avatar
      Chris Coyier
      Permalink to comment#

      Sorry to be such an inconvenience! I appreciate your thoughtful critique.

    • User Avatar
      Trevor Hungerford
      Permalink to comment#

      @Chris Coyier it’s actually a great article. Just messing with a co-worker.

  7. User Avatar
    Dan O
    Permalink to comment#

    I bookmarked this article, and I’ll be referring to it for years I think :) BTW I found a typo: I think you mean “tfoot” rather than “tfood”

    Editor’s note: Thx on the typo. I literally got up to eat lunch right after that section.

  8. User Avatar
    Permalink to comment#

    Really interesting article, thank you for writing it, Chris. Just letting you know there’s a slight typo under ‘Using Emmet for Creating Table Markup’, where ‘perfect’ is spelt ‘prefect’.

    • User Avatar
      Chris Coyier
      Permalink to comment#

      Derp! Must have been reading Hitchhiker’s Guide. #OBSCUREISH REFERENCE

  9. User Avatar
    Diego Riveria
    Permalink to comment#

    Gee just when i am about to start on some long arse 20-30 column table (dont ask thinking about it gives me heartburn) this comes along. What is it with these awesome articles always appearing just when i need them!

    Thanks a mill!

  10. User Avatar
    Permalink to comment#

    Great article! I am definitely bookmarking it. Thanks for your clear and comprehensive treatment.

  11. User Avatar
    Kelly Johnson
    Permalink to comment#

    When I was at Schwab, we had to code email campaigns with tables and only the very basic css was used; font-family, font-size and color. Everything else was pure html because of the number of devices, email clients and browser-based email readers we had to account for (even Lotus Notes!). We went old school and learned a ton of stuff about tables and the one most important deals with width. It was mentioned above but the best way to make sure your table is rock solid for the world; not just the 30% or so who are under 30(!) is to use a controller row….one row and it can be the first one with data but where the widths of the cells are defined and that’s all you need. You don’t need widths defined everywhere; just one row whose cells add up to the width of the table. Soon, copping out and using ” 100%” will be great but for now, if you’re really reaching an audience of at least 1 million or so, then one row defined will be all one needs to debug why in Outlook 2007 in IE 7 a table breaks when even on a blackberry it doesn’t!

  12. User Avatar
    Permalink to comment#

    Wow, what a thorough article. This is my go-to for anything table-related from now!

  13. User Avatar
    Federico Holgado
    Permalink to comment#

    Awesome article, as always Chris! If you want to post some examples of some super complicated tables, check out our subscriber table that we have been refining over the past few releases at MailChimp.

    I’m trying to find a screenshot, but I can’t take one of our list without showing you our subscriber’s emails :( I’ll make a video to show the interaction.

    It has a floating header to allow users to sort at any point, and also has a fixed first column (the email column) so that the user always has context as to what they’re looking at. This table can get so big and nasty for some users that we really wanted to make it work well.

    In order to get the floating header + the horizontal overflow scrolling to work properly, we essentially cloned the table thead, and in order for the cloned table header to scroll simultaneously with the body, we had to set up some JS listeners to update the scrollLeft value on the new thead based on the table body value.

    We’re still working out the best way to make it work on a small screen, not quite there yet.

    Lots of super crazy stuff, but it was a lot of fun to work on!

  14. User Avatar
    Michael Whyte
    Permalink to comment#

    Hands down…the best article I have ever read on tables…period….Just awesome….Thanks for taking the time to write an amazing blog post…I am sure this will be reference material for many people for quite a while…

  15. User Avatar
    Permalink to comment#

    Hey Chris thanks for the wonderful article on the tables now i know the all about the tables… thanks Chris for the post….>!

  16. User Avatar
    Ramesh Chowdarapally
    Permalink to comment#

    This is really nice and deep write up. some bugs are there. Overall nice chris.

  17. User Avatar
    Permalink to comment#

    Wow (bookmarked)! This has got to be one of the most in-depth write up on tables in a single post. Nice job.

    Two additional behaviours to consider:

    1) AP/RP is not honored cross browser ( FF, ignores AR/RP); One reason why using CSS tables for layout is still ‘imperfect’

    2) Margins on a table/display:table element work similar to floats ( and, of course, dont work at all on TD, TH,TR, etc)

    • User Avatar
      Permalink to comment#

      oops.. I saw the part on AP… on my second re read :: red face::

  18. User Avatar
    Permalink to comment#

    Great article. I was looking forward to the bit on HTML emails though?

    The last holdout is HTML emails, which we’ll get into later.

    Perhaps in a follow-up article? :)

  19. User Avatar
    Dicky Dwijanto
    Permalink to comment#

    Nice and comprehensive guide on good ol’ table html tag. Even in tableless design trend, it’s hard to completely ignore table tag. Thanks for sharing.

  20. User Avatar
    Amit Kumar
    Permalink to comment#

    Nice, In depth article

  21. User Avatar
    David Randell
    Permalink to comment#

    Holy Cow that was comprehensive. I challenge anyone to find something Chris left out!

    Nice work

    • User Avatar
      Permalink to comment#

      I got one, or if it’s in there I missed it…

      The unique centering of anything inside a cell. For example, if you make one cell the size of the whole screen, and put a 10px square image in it, it will automatically go to the center, vertically and horizontally. As far as I know display:table-cell is the only thing that does this without some kind of script.

  22. User Avatar
    Permalink to comment#

    I found many resources from “css-trics”since i search Google;
    I learn many more things from Chris Coyier Lynda tutorial.
    He is really a experienced & nice person.

  23. User Avatar
    Permalink to comment#

    I think you missed a very important aspect of the colspan and rowspan attributes – how to make a cel take up 100% of table width(i’m not sure if it’s possible with height) regardless of the actual number of cels in a row.

  24. User Avatar
    Permalink to comment#

    A very thorough write-up, as always. And good to see accessibility and RWD considerations mentioned.

  25. User Avatar
    Peter Müller
    Permalink to comment#

    In HTML5 a source order of thead -> tbody -> tfoot is actually okay:

    The table element now allows the tfoot element to be the last child.

    Source: W3C – HTML5: Differences from HTML4

  26. User Avatar
    Permalink to comment#

    this is a masterpiece! thanks!

  27. User Avatar
    Nils Wittler
    Permalink to comment#

    Now that is quality content! Especially the part regarding the responsive styling of tables. If I have to deal with it in the future I will definetly come back to this article and the codepen collection!

  28. User Avatar
    Gunnar Bittersmann
    Permalink to comment#

    Nice summarizing article.

    When you use <thead>, there must be no <tr> that is a direct child of <table>

    is not correct. It has been allowed in HTML 4/XHTML 1, and still is in HTML5:

    “…a thead element, followed optionally by a tfoot element, followed by either zero or more tbody elements or one or more tr elements…”

  29. User Avatar
    Permalink to comment#

    It’s worth noting that <tr> elements will automatically be wrapped by <tbody> whether or not you write <tbody> in the source. This is similar to how the contents of the page will be wrapped with <body> even if your markup is:

    <!doctype html>
    <p>lorem ipsum</p>

    Because of this I recommend that developers always wrap their <tr> elements with <tbody> to avoid confusion.

  30. User Avatar
    Jérôme Coupé
    Permalink to comment#

    On using table-related properties to lay out other elements than tables, I will just cite Eric Meyer in 2009:

    And please, let’s put the whole “display: table-cell will grant those abilities through CSS” to rest. Saying that is just saying “use tables for layout” with different words. Turning a bunch of divs or list items or whatever into table-role boxes is no better than just using table markup in the first place, and it’s arguably worse. Using element names other than table and td to create layout tables, and then claiming it’s not using tables for layout, borders on self-deception.

    Not to mention doing things that way means you’re doing your layout in a highly source-order-dependent fashion, which was one of the things about table layout we were trying to get away from in the first place.

    Source: Wanted: Layout System

    • User Avatar
      Permalink to comment#

      I’ll have to disagree with the great E. Meyer here: abusing HTML elements for their default rendering whatever their semantics is unrelated to using CSS properties and values on HTML elements!

      CSS doesn’t change the semantics of HTML code: it styles it.
      display property exists for a reason and table or table-cell are perfectly fine values. Except replaced elements (img, input, etc), they can be used wherever we want

      CSS table layouts obtained via table or table-cell have interesting properties like staying on a single row, self-adapting widths to content or not, easy vertical centering or same height neighbour elements.
      I’m OK with the title of its post: we need(ed) other layout systems than existing ones because floats, positioning and table layouts aren’t sufficient to address all cases.

  31. User Avatar
    John C
    Permalink to comment#

    Another great article. Perhaps I missed this but please clarify for me on the Responsive Tables. Is the table that is listed as Responsive using Media Queries to get it properly sized? The table listed as RWD List-to-table. Is this using the “Responsive Elements” js that you wrote about on Sep. 17 in “Responsive Elements” blog post? The CSS mentions the need for “respond.js polyfill” for IE and that’s new to me.

    I’m of the opinion that there is no reason to make a table on a site if it isn’t going to be responsive so I’m trying to get clarity on which approach is best. Putting js script all over my site has me cautious due to possible conflicts so I use it selectively.

    • User Avatar
      Permalink to comment#

      Hey John,

      I wrote the Codepen example you’re talking about. Keep in mind it was proof of concept only.

      The respond.js is only needed for IE8 and lower because a) they don’t support media queries, b) the scss is written to be mobile first; therefore IE8,7 display the css incorrectly.

      The css could be written for large displays and then back down to smaller screens. However, I find mobile-first css faster to write and would rather save time developing rather than wasting time supporting old browsers. Serving respond.js for IE8 and 7 allows them to correctly read the media queries.

  32. User Avatar
    Permalink to comment#

    Fantastic article. This is the ULTIMATE table guide

  33. User Avatar
    Permalink to comment#

    Thanks for writing on this.

    I can’t tell you the countless times I’ve been confused on tables.

  34. User Avatar
    Permalink to comment#

    Nice artical but very poor cross-browser compatibility.

    • User Avatar
      Permalink to comment#

      The table tag has probably the best cross-browser compatibility (way better than any CSS based approach) since it’s been used since the very beginning of HTML…

  35. User Avatar
    Rick H
    Permalink to comment#

    Nice article! I particularly liked the sorting functions without having to have the data being fed from a database.

    And the use of tables as a layout tool is one of the things that gets me gnashing my teeth when I look through the code on WordPress pages!

  36. User Avatar
    Permalink to comment#

    This is an excellent article, the examples are extremely helpful. I just stumbled across this site a few days ago and you’ve won a regular reader. Great work.

  37. User Avatar
    Permalink to comment#

    Great article !

    With regards to the ‘Fixed Header Table’ look at my solution I am using within my projects.

    A demo and the code can be found at


  38. User Avatar
    Mark LeMerise
    Permalink to comment#

    Is it bad that I didn’t know about the rowspan attribute until today? Yet another great guide, Chris. Well done!

  39. User Avatar
    Permalink to comment#

    Very helpfull :) more such tutorials should be provided .. ! :)

  40. User Avatar
    Attiq -ur- Rehman
    Permalink to comment#

    Very informative and useful post, thanks.

  41. User Avatar
    Permalink to comment#

    Hi Chris!

    I made some (maybe) interesting workaround solution for displaying tables on responsive websites … Here is a link if someone is interested ( I used your CSS model with some new JS ):

  42. User Avatar
    Permalink to comment#


  43. User Avatar
    Permalink to comment#

    I consider myself an HTML veteran, having started my journey writing html (and consequently, tables) in 1997/1998 and made the transition from using tables for layout, to div layouts, but even I learned a thing or two with this article… mainly about styling tables with CSS (I never new about the CSS property border-spacing) and this is absolutely essential for anyone learning html today. Bookmarked!!

    That said I have noticed more and more emails are being structured with divs and css, and even are responsive. I am so ready to be done with the archaic table layouts, but I haven’t tried any of these new methods yet.

  44. User Avatar
    Permalink to comment#

    This article is really helpful. I just bookmarked it for future reference. I especially like the demo on live searching through table data through using jQuery or JavaScript. I also like that this article has so many examples and code snippets. It’s the best article on tables I’ve ever read.

  45. User Avatar
    Permalink to comment#

    Thanks for this post, Chris. Some really great examples of styling tables as well.

    I’m looking for a really good example of using ul and li elements to create beautiful, responsive multi-column lists (nested?) like you would see in an email application or on a social media feed. Multi-column list search results are usually examples of article-like content spanning columns of a page.

    I think what I’m looking for requires a simple grid structure inside the list elements, but I’m sure there are many CSS quirks across devices. An email example similar to iOS’ built in mail app would be perfect, can anyone point me toward this?

    I’ll search your site for it of course :).

  46. User Avatar
    Permalink to comment#

    Very thorough article! Just missing the one thing I’ve been searching for—row highlighting by clicking a checkbox like phpMyAdmin, or even just clicking somewhere in the row. Hover is nice, but I’ve got some databases which need a horizontal scroll. Highlighting a row with hover doesn’t help when you have to move the cursor to scroll.

    • User Avatar
      Permalink to comment#

      You need some js to do this.

      In your css, create a selected class and give it whatever background you want.

      And in your js,

      $('table tr').click(function() {

      You can also attach an event listener to the checkbox if you want to use a checkbox and make it toggle the selected class.

  47. User Avatar
    Manzoor Kottayil
    Permalink to comment#

    For getting a better user experience, please make the code-pen boxes as re sizable. It will help us to see the things in a very good manner.

  48. User Avatar
    Alistair Chisholm
    Permalink to comment#

    Hey Chris. Good stuff. I’m wondering what the rules are regarding correctly using an <a href=""> in amongst table markup.

    Is it alright to wrap a whole table row inside a link?
    Is it alright to wrap a pile of<td>sinside a link?
    Or do you think we should only ever use links inside a <td>?

    • User Avatar
      Permalink to comment#

      That’s actually a good question, because HTML5 now allows anchor elements (“a”) to wrap mostly anything, even block elements. But I tested it out and, as expected, not only does it fail validation, but it doesn’t seem to do anything (at least not in Chrome).

  49. User Avatar
    Tim Iles
    Permalink to comment#

    Regarding the comments about where to position <tfoot>:

    Be aware that if the user copies a table and pastes it elsewhere, the rows will appear in DOM order, even if the browser displays the footer correctly. If your audience is likely to do this often (eg regularly pasting data into Excel), you can cause less confusion by putting <tfoot> after <tbody>.

  50. User Avatar
    Ejaz hunzai
    Permalink to comment#

    What a fantastic post I have read today. Display property can also be used to display any element as a table. Wonder to know. Thanks Chris. :)

  51. User Avatar
    Patrik Alienus
    Permalink to comment#

    Amazing post. Undoubtedly the most extensive and well thought out post on tables I have ever seen.

  52. User Avatar
    Permalink to comment#

    Really great article !

    I want to submit a semantic question about table…

    I frequently use table to display forms, in a three columns way : label, input field and help/info area, repeating lines to lines for each data… a more easy way to construct form.

    My hypothesis is than the data are tabulars, associated:

    each line is a coherent set (label / input / help)
    the entire form represent a way to input … a line in a database, so…)

    Some of my colleague said NO! It’s “old school”, you need to use ul / li / div … and float or display: table* … (so, in my opinion, lot’s of css to do the same, and less semantic)…

    Who is (more) correct?

  53. User Avatar
    Permalink to comment#

    I wish you would have spent more than just a fleeting moment on the scope attribute.

    So many designers skipping the accessibility part of design, and I personally feel it is an often overlooked duty as a professional to make sure to the best of ones ability that content is accessible.

    Trust me, one you’ve dug through the American’s with Disabilities Act, specifically (section508a), it is vitally important to encourage businesses to make their sites/storefronts accessible to those with disabilities. Not only to be inclusive, not exclusive to their visitors, but to also avoid legal troubles.

    I remember years ago the Target corporation got into hot water because a “non-sighted” or blind man could not navigate their menu, and as a result, filed a lawsuit. Target quickly changed their navigation shortly thereafter.

    Don’t get me wrong, the article was an excellent repository of best practices, etc., but as a designer, and someone that teaches design for a local college (yes, I have broken the ‘those who can’t do, teach’ mold), I encourage my students to put accessibility just as high as any other design methodology/ideology.

  54. User Avatar
    Permalink to comment#

    Great article!

  55. User Avatar
    Permalink to comment#

    This was very worthwhile reading, so thanks! A couple of typos, for example I think “on” should be “one”, but great information. I confess that I’ve used tables in the header and footer to position elements when floating divs weren’t behaving nicely. You’ve shown me a way to make those divs behave and get rid of those tables.

  56. User Avatar
    Permalink to comment#

    You say “Rarely do you see modern websites touch tables for layout.”

    Take a look at …. Tables everywhere !

  57. User Avatar
    Permalink to comment#

    Watch out for vertical-align: baseline settings on the <td> tag in the Meyer’s Reset CSS!

    I recently ran into a strange situation where two side-by-side table cells, one with text and the other with an image, didn’t align properly, and it took awhile until I figured out it was because of the vertical-align settings in the CSS Reset.

    Example on CodePen

  58. User Avatar
    Permalink to comment#

    please @chris how can i use the table data content for a particular table,because all the tables on my website are inheriting this style.

  59. User Avatar
    Permalink to comment#

    I haven’t read all the comments to see if someone else already mentioned this, but…

    In the example of sorting a table, the script is only seeing the numbers before a comma. Example, the number 2,234 would sort lower than the number 456, and higher than 1,234,567.

  60. User Avatar
    Rahul Tiwary
    Permalink to comment#

    This article is really helpful. I just bookmarked it for future reference. I especially like the demo on live searching through table data through using jQuery or JavaScript. I also like that this article has so many examples and code snippets. It’s the best article on tables I’ve ever read.

  61. User Avatar
    sachin suryavanshi
    Permalink to comment#

    Hey Hi,
    I have one data in tabular structure where second column have Lorem Ipsum
    Now, I want to write css on Focus of link.

    Currently i wrote code and css on a:focus which is working fine except web kit browser like crome & safari.

    Do we have any other alternative to implement this?

  62. User Avatar
    Permalink to comment#

    Nice article.

    I have a question, how you would make the table to have behaviors such as the DataGrid in Flex? I mean to be able to drag the borders of the columns to change their width (like in a spreadsheet as well).

  63. User Avatar
    Permalink to comment#

    Hi, I’m having a problem adapting 2 variable tables in the same div.

    I have a main div containing 2 tables, both have to have variable width, the only thing I know is the left hand side table could come with 2, 3, 4, 5 or 6 columns, but have to have a max width of 39% (in the case is coming with 6 columns)

    The right hand side table has to adapt the remaining space from the left hand table, and the max width this table would have (imaging that the left hand side table has only 2 columns) is 83% more or less.

    Do you have any ideas how to adapt both in the same div without jumping next line and make both adapting to the 100% div space?

    Thanks in advance, Marian.

  64. User Avatar
    Permalink to comment#

    Great article. I don’t know much HTML / CSS. This helped me to quickly create a HTML table.

  65. User Avatar
    Permalink to comment#

    Good stuff, thank you!

    Noticed repeating ids in one of the filtering examples and instead of internet-commenting about it, thought I’d fix it on codepen and share it. if you’d like to update it.

    Thanks again!

  66. User Avatar
    Permalink to comment#

    Something else that might be considering is using Jquery to dynamically size your table elements. Although this could be a bit of a head scratcher unless you are already converting a template to start of with. Google is your friend.

  67. User Avatar
    Permalink to comment#

    As usual, simply excellent. Actually I was looking for something a little different, but this was among my search results: “A complete guide to the table element” by Chris Coyier. Got to be worth reading I thought. Dead right :)

    I see you mention tablesorter and link to an article giving many more such resources, including the very comprehensive Some might want to investigate jtable which I’ve found good (I note most jtable functionality is available without further plugins).

    Thanks again for a great article.

  68. User Avatar
    Permalink to comment#

    Great guide.

    I wonder if you or anyone can help me with a table problem – I want to have a 2 column table with several rows but the only border I want in the right hand side of column 1. The effect would be a vertical line between the two columns.

    Any help greatly appreciated.

  69. User Avatar
    Permalink to comment#

    Since I only work on web applications that sit behind authentication I completely avoid using the table element and it saves me a ton of time and headaches. The table and associated elements are unpredictable and have too much quirkiness for my liking.

  70. User Avatar
    Permalink to comment#

    Very useful post, thank you.

    Maybe someelse already told you but can I suggest a little change in your javascript code for the “simple search” in table. In order to select the rows under the header you use
    var rows = $('table tr:gt(0)');
    I suggest to use
    var rows = $('tbody tr');
    I had a problem when I used your code with a two rows header.

  71. User Avatar
    Daniel Ferro

    Nothing wrong with using tables for layout. Yes it is a hack, but so is using CSS and DIVs for layout. Neither were intended for layout. And tables have much better inherit properties that make them ideal for layout purposes. If content within a cell is wider than the cell width, the cell will stretch to accommodate the content, and all surrounding cells will stretch as well.

    I have done extensive work with Section 508. Layout tables present no accessibility problems if used correctly (don’t use THs if it is just a layout table, and for goodness sakes do not give the table a caption or summary at all if it just a layout table). I really am baffled by the modern web design communities demonization of layout tables.

    It’s just a tool guys. If it works across the browsers you need it to, if it functions as intended and presents no accessibility problems, by all means use it. Using layout tables intermingled with layout DIVs can be a great best of both world approaches to get your site done fast.

    If it works use it.

icon-link icon-logo-star icon-search icon-star