Lesson 9

Organizing Data with Tables

When HTML was coming to life tables were used all over the place, and were the primary means by which websites were built. They were used for positioning content as well as building the overall layout of a page. Fortunately we have come a long way since then. Today tables are, and should be, used specifically for organizing data.

When dealing with large amounts of tabular data tables are the go to foundation for displaying this information. Using tables provides a quick and easy way to both read and digest information, giving users an overall understanding of the data.

Reserving tables for data, not page design, still has challenges. How a table should be built in HTML is largely dependent on the data and how it is to be displayed. Upon being marked up in HTML, tables need to be stylized with CSS to make the information more comprehensive and understandable to users.

Creating a Table

In general tables are made up of data within rows and columns. Depending on the table these rows and columns will correlate to one another accordingly. In HTML, there are a few different elements needed to make a table. At a minimum a table must consist of table, tr, and td elements. To take tables one step further they may include the th element as well. Getting all of these elements to work together builds a solid table.

Table

To initialize a table on a page the table element is used. Using the table element signifies that the data within these tags will be displayed in two or more dimensions. The table element is only an initializer and it must encompass a table row, along with table data.

<table>
  ...
</table>

Table Row

Once the table has been defined in HTML, table rows may be added using the tr element. A table can have numerous table rows, or tr elements. Depending on the amount of information the number of table rows can be substantially high. To add data into these table rows the table data, td, and table header, th, elements are used.

<table>
  <tr>
    ...
  </tr>
  <tr>
    ...
  </tr>
</table>

Table Data

The best way to add data to a table is via the table data, or td element. The table data element creates a cell, of which may include data. Listing multiple table data elements one after the other will create columns within a table row. When the contents of a cell is a heading for either a row or column it should be wrapped within the table header element, th, not the table data element, td.

<table>
  <tr>
    <td>Date</td>
    <td>Opponent</td>
    <td>Location</td>
    <td>Time</td>
  </tr>
  <tr>
    <td>Monday, March 5th</td>
    <td>Indiana Pacers</td>
    <td>United Center, Chicago, IL</td>
    <td>7:00 PM</td>
  </tr>
  <tr>
    <td>Wednesday, March 7th</td>
    <td>Milwaukee Bucks</td>
    <td>Bradley Center, Milwaukee, WI</td>
    <td>7:00 PM</td>
  </tr>
  <tr>
    <td>Thursday, March 8th</td>
    <td>Orlando Magic</td>
    <td>United Center, Chicago, IL</td>
    <td>7:00 PM</td>
  </tr>
  <tr>
    <td>Saturday, March 10th</td>
    <td>Utah Jazz</td>
    <td>United Center, Chicago, IL</td>
    <td>7:00 PM</td>
  </tr>
</table>

Table Data Demo

Date Opponent Location Time
Monday, March 5th Indiana Pacers United Center, Chicago, IL 7:00 PM
Wednesday, March 7th Milwaukee Bucks Bradley Center, Milwaukee, WI 7:00 PM
Thursday, March 8th Orlando Magic United Center, Chicago, IL 7:00 PM
Saturday, March 10th Utah Jazz United Center, Chicago, IL 7:00 PM

Table Header

To designate a heading for a column or row of cells the table header element, th, should be used. The table heading element works just like that of the table data element in that it creates a cell for data. The value to using the table header element over the table data element is that the table header provides a semantic value to table, signifying the data within the cell as a heading. The two elements are comparable to that of a heading, h1, and paragraph, p. While a heading’s content could be placed within a paragraph tag it doesn’t make sense to do so. Using a heading tag specifically adds more value to the content and provides an easier way to stylize all headings. The exact same is true for headers within tables.

Table headers are available to use within both rows and columns. The table data will determine where the headers are placed. To help the headers in noting exactly what content they pertain to the scope attribute is available. The scope attribute signifies whether a header applies to a row or column with the values row, col, rowgroup, and colgroup. The most commonly used values are row and col. The row value notes that every cell within the row relates directly to that header, and the col value notes that every cell within the column relates directly to that header.

The Headers Attribute

Very similar to the scope attribute is the headers attribute. By default the scope attribute may only be used on the th element. In the case that a cell, either a td or th, needs to be associated with a different header the headers attribute comes into play. The value of the headers attribute on a td or th needs to match the id of the th that cell pertains to.

Additionally, depending on the browser, table headers may also appear bold and centered. Should these default styles not be the preferred styling they may be over written in CSS.

<table>
  <tr>
    <th scope="col">Date</th>
    <th scope="col">Opponent</th>
    <th scope="col">Location</th>
    <th scope="col">Time</th>
  </tr>
  <tr>
    <td>Monday, March 5th</td>
    <td>Indiana Pacers</td>
    <td>United Center, Chicago, IL</td>
    <td>7:00 PM</td>
  </tr>
  <tr>
    <td>Wednesday, March 7th</td>
    <td>Milwaukee Bucks</td>
    <td>Bradley Center, Milwaukee, WI</td>
    <td>7:00 PM</td>
  </tr>
  <tr>
    <td>Thursday, March 8th</td>
    <td>Orlando Magic</td>
    <td>United Center, Chicago, IL</td>
    <td>7:00 PM</td>
  </tr>
  <tr>
    <td>Saturday, March 10th</td>
    <td>Utah Jazz</td>
    <td>United Center, Chicago, IL</td>
    <td>7:00 PM</td>
  </tr>
</table>

Table Header Demo

Date Opponent Location Time
Monday, March 5th Indiana Pacers United Center, Chicago, IL 7:00 PM
Wednesday, March 7th Milwaukee Bucks Bradley Center, Milwaukee, WI 7:00 PM
Thursday, March 8th Orlando Magic United Center, Chicago, IL 7:00 PM
Saturday, March 10th Utah Jazz United Center, Chicago, IL 7:00 PM

Combining Multiple Cells

There often comes a time when two or more cells will need to be combined into one without breaking the overarching row and column layout. Perhaps two cells next to each other contain the same data, or the cells need to be combined for stylization purposes. In this case we can use the colspan and rowspan attributes. These two attributes work on either the table data or table header elements.

The colspan attribute is used to span a cell across multiple columns within a table, where the rowspan attribute is used to span a cell across multiple rows. Each attribute accepts an integer value indicating the number of cells to span across, with 1 being the default value.

<table>
  <tr>
    <th scope="col">Date</th>
    <th scope="col">Opponent</th>
    <th scope="col">Location</th>
    <th scope="col">Time</th>
  </tr>
  <tr>
    <td>Monday, March 5th</td>
    <td>Indiana Pacers</td>
    <td>United Center, Chicago, IL</td>
    <td rowspan="4">7:00 PM</td>
  </tr>
  <tr>
    <td>Wednesday, March 7th</td>
    <td colspan="2">Milwaukee Bucks, Bradley Center, Milwaukee, WI</td>
  </tr>
  <tr>
    <td>Thursday, March 8th</td>
    <td>Orlando Magic</td>
    <td rowspan="2">United Center, Chicago, IL</td>
  </tr>
  <tr>
    <td>Saturday, March 10th</td>
    <td>Utah Jazz</td>
  </tr>
</table>

Combining Multiple Cells Demo

Date Opponent Location Time
Monday, March 5th Indiana Pacers United Center, Chicago, IL 7:00 PM
Wednesday, March 7th Milwaukee Bucks, Bradley Center, Milwaukee, WI
Thursday, March 8th Orlando Magic United Center, Chicago, IL
Saturday, March 10th Utah Jazz

Table Structure

Knowing how to build a table and arrange data is extremely powerful, and a skill set necessary for every front-end developer. On top of building table rows and cells there are a few additional elements to help us organize data within a table. These elements include caption, thead, tfoot, and tbody.

Table Caption

To provide a caption or title for a table the caption element is used. A caption will help users identify what the table pertains to and what they can expect within it. The caption element must come immediately after the opening table tag. Its position is at the top of the table by default, however may be changed using CSS. Should a table fall within the figure element, the figcaption element should be used in place of the caption element.

<table>
  <caption>Chicago Bulls Schedule - Week of March 5th</caption>
  ...
</table>

Table Caption Demo

Chicago Bulls Schedule - Week of March 5th
Date Opponent Location Time
Monday, March 5th Indiana Pacers United Center, Chicago, IL 7:00 PM
Wednesday, March 7th Milwaukee Bucks Bradley Center, Milwaukee, WI 7:00 PM
Thursday, March 8th Orlando Magic United Center, Chicago, IL 7:00 PM
Saturday, March 10th Utah Jazz United Center, Chicago, IL 7:00 PM

Table Head, Body, & Foot

Tables can be broken up into multiple groups, including a header, footer, and body. The elements to help better organize a table are thead for a table header, tbody for a table body, and tfoot for a table footer.

The table header element, thead, wraps the heading row, or rows, of a table denoting the heading. The table header should be placed at the top of a table, after any caption and before any tbody.

Following the table header may come either the table body or table footer elements. Originally the tfoot element had to come immediately after the thead, however HTML5 has provided leeway here. They may now come in any order so long as they are never the parent element of one another. Moving forward, the tbody element should contain the primary data within the table, while the tfoot contains data that outlines the contents of the table.

Table Head, Body, & Foot<table>
  <caption>...</caption>
  <thead>
    ...
  </thead>
  <tbody>
    ...
  </tbody>
  <tfoot>
    ...
  </tfoot>
</table>

Table Borders

One design component used to help make tables more comprehensible are borders. Borders around a table, rows, or individual cells can make a large impact when trying to interpret data and quickly scan for information. When stylizing table borders with CSS there are two properties that will quickly come in hand, they are the border-collapse and border-spacing properties.

Border Collapse Property

Tables consist of a parent table element as well as subsequent td elements. Applying a border to both of these elements will begin to stack up borders all around. Take for example, putting a 2 pixel border around an entire table and then an additional 2 pixel border around each table cell. In return this would create a 4 pixel border around every cell within the table.

The border-collapse property determines a tables border model. There are three values for the border-collapse property, including collapse, separate, and inherit. By default the value is separate meaning that all of the different borders will stack up to one another accordingly, like mentioned above. The collapse property, on the other hand, will condense the borders down to one, choosing the table cell as the primary border.

table {
  border: 2px solid blue;
  border-collapse: separate;
}
th, td {
  border: 2px solid red;
}

Border Collapse Property Demo

  • Luke Brad
    88 76

    separate

  • Luke Brad
    88 76

    collapse

Border Spacing Property

Understanding that the border-collapse property with the separate values allows borders to be stacked up against one another the border-spacing property can determine how much space, if any, appears between the borders. Going back to our example, a table with a 2 pixel border and a 2 pixel border around each cell creates a 4 pixel border all around. Adding in a border-spacing value of 2 pixels would then separate the two borders by 2 pixels, creating a 6 pixel total border width.

table {
  border: 2px solid blue;
  border-collapse: separate;
  border-spacing: 2px;
}
th, td {
  border: 2px solid red;
}

Border Spacing Property Demo

Luke Brad
88 76

Adding in Borders

Putting a border around a table is fairly simple, however putting borders around rows or cells can be more difficult. Below are a few examples of how to add these borders. For an additional reference and examples on how to add borders around a table check out the tables within Bootstrap, from Twitter.

Row Borders

Putting a border between each row is as simple as adding a bottom border to each table cell. To remove the bottom border of the cells within the last row of the table the pseudo-class last-child selector is used.

table {
  border-collapse: collapse;
  border-spacing: 0;
}
th, td {
  border-bottom: 1px solid #c6c9cc;
}
tr:last-child td {
  border: 0;
}

Row Borders Demo

Track Artist Length
We Are Young Fun. 4:10
Pumped Up Kicks Foster the People 3:59
Midnight City M83 4:03

Cell Borders

On the other hand, putting a border around every individual cell is fairly easy. Simply put a border around each table header or table data cell and set the overall table to have a border-spacing value of collapse.

table {
  border-collapse: collapse;
  border-spacing: 0;
}
th, td {
  border: 1px solid #c6c9cc;
}

Cell Borders Demo

Track Artist Length
We Are Young Fun. 4:10
Pumped Up Kicks Foster the People 3:59
Midnight City M83 4:03

Aligning Text

In addition to table borders, aligning text within cells, both horizontally and vertically, plays an integral part of table formatting. Commonly names, descriptions, and so forth are flush left while numbers and figures are flush right. Other information, depending on its context, should be centered. Moving text horizontally can be accomplished using the text-align property within CSS, as covered in the typography lesson.

To align text vertically the vertical-align property is used. The vertical-align property only works with inline and table-cell display elements. That said, the vertical-align property will not work for block level or any other level elements.

The vertical-align property accepts a handful of different values, of which change depending on if the element is displayed as an inline and table-cell element. Within tables the most popular values include top, middle, and bottom. These values then vertically position text within the cell in relation to their value.

HTML
<table>
  <thead>
    <tr>
      <th colspan="2">Items</th>
      <th class="qty">Qty</th>
      <th class="price">Price</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td class="item">Envisioning Information <span>By Edward R. Tufte – Hardcover</span></td>
      <td class="stock in">In Stock</td>
      <td class="qty">1</td>
      <td class="price">$33.32</td>
    </tr>
    <tr>
      <td class="item">Outliers <span>By Malcolm Gladwell – Hardcover</span></td>
      <td class="stock in">In Stock</td>
      <td class="qty">2</td>
      <td class="price">$33.58 <span>($16.79 × 2)</span></td>
    </tr>
    <tr>
      <td class="item">Don’t Make Me Think <span>By Steve Krug – Paperback</span></td>
      <td class="stock out">Out of Stock</td>
      <td class="qty">1</td>
      <td class="price">$22.80</td>
    </tr>
    <tr>
      <td class="item">Steve Jobs <span>By Walter Isaacson – Hardcover</span></td>
      <td class="stock in">In Stock</td>
      <td class="qty">1</td>
      <td class="price">$17.49</td>
    </tr>
  </tbody>
  <tfoot>
    <tr class="sub">
      <td colspan="3">Subtotal</td>
      <td>$107.19</td>
    </tr>
    <tr class="tax">
      <td colspan="3">Tax</td>
      <td>$10.71</td>
    </tr>
    <tr class="total">
      <td colspan="3">Total</td>
      <td>$117.90</td>
    </tr>
  </tfoot>
</table>
CSS
table {
  border-collapse: collapse;
  border-spacing: 0;
}
th, td {
  border: 1px solid #c6c9cc;
  vertical-align: top;
}
th {
  font-size: 11px;
  text-transform: uppercase;
}
th.qty, th.price {
  text-align: center;
}
tbody td.item {
  color: #404853;
  font-weight: bold;
}
tbody td.stock, tbody td.qty, tbody td.price {
  vertical-align: middle;
}
tbody td.stock, tbody td.qty {
  text-align: center;
}
tbody td.price {
  text-align: right;
}
tfoot td {
  text-align: right;
}
tfoot tr.sub td, tfoot tr.tax td {
  color: #8c8c8c;
  font-size: 12px;
}
tfoot tr.total td {
  color: #404853;
  font-size: 14px;
  font-weight: bold;
}
.in {
  color: #00b515;
}
.out {
  color: #b50000;
}
span {
  color: #8c8c8c;
  display: block;
  font-size: 12px;
  font-weight: normal;
}

Aligning Text Demo

Items Qty Price
Envisioning Information By Edward R. Tufte – Hardcover In Stock 1 $33.32
Outliers By Malcolm Gladwell – Hardcover In Stock 2 $33.58 ($16.79 × 2)
Don’t Make Me Think By Steve Krug – Paperback Out of Stock 1 $22.80
Steve Jobs By Walter Isaacson – Hardcover In Stock 1 $17.49
Subtotal $107.19
Tax $10.71
Total $117.90

Table Striping

In the effort to help make tables more legible, one common pattern is to "stripe" the table rows so that they alternate background colors. This makes the rows more identifiable and provides a great visual cue for scanning information. One way to do this is to place a class on every other row and set a background color to that class. Another way is to use the nth-child pseudo-class selector and set the select to odd or even rows.

th {
  background: #404853;
  background: linear-gradient(#687587, #404853);
  color: #fff;
}
tbody tr:nth-child(even) td {
  background: #e8eae9;
  background: linear-gradient(#f7faf9, #e8eae9);
}
tfoot tr.total td {
  background: #e8eae9;
  background: linear-gradient(#f7faf9, #e8eae9);
}

Table Striping Demo

Items Qty Price
Envisioning Information By Edward R. Tufte – Hardcover In Stock 1 $33.32
Outliers By Malcolm Gladwell – Hardcover In Stock 2 $33.58 ($16.79 × 2)
Don’t Make Me Think By Steve Krug – Paperback Out of Stock 1 $22.80
Steve Jobs By Walter Isaacson – Hardcover In Stock 1 $17.49
Subtotal $107.19
Tax $10.71
Total $117.90

Full Featured Table Completely Styled

HTML
<table>
  <thead>
    <tr>
      <th class="item" colspan="2">Items</th>
      <th class="qty">Qty</th>
      <th class="price">Price</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td class="item">Envisioning Information <span>By Edward R. Tufte – Hardcover</span></td>
      <td class="stock in">In Stock</td>
      <td class="qty">1</td>
      <td class="price">$33.32</td>
    </tr>
    <tr>
      <td class="item">Outliers <span>By Malcolm Gladwell – Hardcover</span></td>
      <td class="stock in">In Stock</td>
      <td class="qty">2</td>
      <td class="price">$33.58 <span>($16.79 × 2)</span></td>
    </tr>
    <tr>
      <td class="item">Don’t Make Me Think <span>By Steve Krug – Paperback</span></td>
      <td class="stock out">Out of Stock</td>
      <td class="qty">1</td>
      <td class="price">$22.80</td>
    </tr>
    <tr>
      <td class="item">Steve Jobs <span>By Walter Isaacson – Hardcover</span></td>
      <td class="stock in">In Stock</td>
      <td class="qty">1</td>
      <td class="price">$17.49</td>
    </tr>
  </tbody>
  <tfoot>
    <tr class="sub">
      <td class="title" colspan="3">Subtotal</td>
      <td class="price">$107.19</td>
    </tr>
    <tr class="tax">
      <td class="title" colspan="3">Tax</td>
      <td class="price">$10.71</td>
    </tr>
    <tr class="total">
      <td class="title" colspan="3">Total</td>
      <td class="price">$117.90</td>
    </tr>
  </tfoot>
</table>
CSS
table {
  border-collapse: separate;
  border-spacing: 0;
}
th, td {
  vertical-align: top;
}

th {
  background: #404853;
  background: linear-gradient(#687587, #404853);
  border-left: 1px solid rgba(0, 0, 0, 0.2);
  border-right: 1px solid rgba(255, 255, 255, 0.1);
  color: #fff;
  font-size: 11px;
  padding: 9px 8px 7px 8px;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.6);
  text-transform: uppercase;
}
th.qty, th.price {
  padding: 9px 20px 7px 20px;
  text-align: center;
}
th.item {
  border-left: 0;
}
th.price {
  border-right: 0;
}
td {
  padding: 8px;
}
tbody td {
  border-bottom: 1px solid #c6c9cc;
  border-left: 1px solid #e4e7eb;
  border-right: 1px solid rgba(255, 255, 255, 0.6);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.6);
}
tbody tr:nth-child(even) td {
  background: #e8eae9;
  background: linear-gradient(#f7faf9, #e8eae9);
  border-left: 1px solid #d5d8db;
}
tbody td.item, tbody tr:nth-child(even) td.item {
  border-left: 1px solid #c6c9cc;
}
tbody td.item {
  color: #404853;
  font-weight: bold;
}
tbody td.stock, tbody td.qty, tbody td.price {
  vertical-align: middle;
}
tbody td.stock, tbody td.qty {
  text-align: center;
}
tbody td.price {
  border-right: 1px solid #c6c9cc;
  text-align: right;
}
tfoot td {
  border-bottom: 1px solid #c6c9cc;
  border-left: 1px solid #e4e7eb;
  border-right: 1px solid rgba(255, 255, 255, 0.6);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.6);
  text-align: right;
}
tfoot td.title {
  border-left: 1px solid #c6c9cc;
}
tfoot td.price {
  border-right: 1px solid #c6c9cc;
}
tfoot tr.sub td {
  border-bottom: 0;
  padding: 8px 8px 0 8px;
}
tfoot tr.tax td {
  padding: 0 8px 8px 8px;
}
tfoot tr.sub td, tfoot tr.tax td {
  color: #8c8c8c;
  font-size: 12px;
}
tfoot tr.total td {
  background: #e8eae9;
  background: linear-gradient(#f7faf9, #e8eae9);
  color: #404853;
  font-size: 14px;
  font-weight: bold;
}
tfoot tr.total td.price {
  border-left: 1px solid #d5d8db;
}
.in {
  color: #00b515;
}
.out {
  color: #b50000;
}
span {
  color: #8c8c8c;
  display: block;
  font-size: 12px;
  font-weight: normal;
}

Demo

Items Qty Price
Envisioning Information By Edward R. Tufte – Hardcover In Stock 1 $33.32
Outliers By Malcolm Gladwell – Hardcover In Stock 2 $33.58 ($16.79 × 2)
Don’t Make Me Think By Steve Krug – Paperback Out of Stock 1 $22.80
Steve Jobs By Walter Isaacson – Hardcover In Stock 1 $17.49
Subtotal $107.19
Tax $10.71
Total $117.90

Resources & Links

Complete! Any questions?

Please feel free to contact me on Twitter if you have any questions. Also, if you enjoyed this lesson please share it with your friends.

An Advanced Guide to HTML & CSS

An Advanced Guide to HTML & CSS

An Advanced Guide to HTML & CSS takes a deeper look at front-end design & development, teaching the latest for any designer looking to round out their skills.

View the Advanced Guide to HTML & CSS