Skip to main content

8. Tables & Lists

Tables

Tables allow you to format content into rows and columns. The concept is similar to that of spreadsheets.

As is the case with spreadsheets, HTML tables are best used to display data. Using a table to display your data provides a logical structure and can provide semantic information about the content of the table.

Tables should not be used for design or layout purposes. They should be used to logically structure and present data.

Unlike the elements we have discussed so far, tables require several other interdependent elements. The <tr> (table row) element is nested within the <table> element to create a row in your table. Within the <tr>, the <td> (table data) element is used to create the cells which contain the content.

Here is the basic structure of an HTML table:

<table class="fahrvergnugen">
<tr>
<td>Row 1 - Column 1 data</td>
<td>Row 1 - Column 2 data</td>
</tr>
<tr>
<td>Row 2 - Column 1 data</td>
<td>Row 2 - Column 2 data</td>
</tr>
</table>

Notice how I indented the elements using the tab key. It would be a good idea to format your code in this manner. It makes the code so much more readable and easier to maintain.

Also notice that I added a class. A class is not required, but I'm going to use that as the selector in my CSS.

Output without any CSS styling:

HTML table without CSS styling

Styling tables with CSS

There are several HTML attributes for the table element. However, they have been deprecated in HTML5.

Since most of these are HTML attributes that deal with styling, it makes sense to avoid them. It's best to keep all styling in the CSS so you can easily make changes later without disturbing the HTML.

Just in case you missed the previous 352 times I've mentioned this: HTML is for structure and meaning. CSS is for styling.

Let's use the class to apply some CSS styling:

.fahrvergnugen {
border: 1px solid #000;
}

Note that my class name ("fahrvergnugen") is completely meaningless. You could choose your own semantic class name that describes the purpose/meaning of the table.

Or you could just use the element name ("table") as the selector.

Or you could use a descendant selector to target tables within the main element. On a website, you would likely want all tables within your main content to have the same styling:

main table {
border: 1px solid #000;
}

But in this lesson, I'm going to go with the "fahrvergnugen" class because it's fun to say :)

Output:

HTML table with border added with CSS

Now let's add a border to the <td> elements:

.fahrvergnugen {
border: 1px solid #000;
}

.fahrvergnugen td {
border: 1px solid #000;
}

Or, we could (and should) reduce the amount of code by using a group selector. Let's combine those entries:

.fahrvergnugen, .fahrvergnugen td {
border: 1px solid #000;
}

Note that ".fahrvergnugen" IS the table element (I have added that class to the table element in the HTML). And the td is inside the table in our HTML structure.

If I was targeting all tables within the main element, I would use this as the selector:

main table, main table td {
border: 1px solid #000;
}

By default, this will result in a double border:

HTML table example with border added to table and td elements with CSS

To fix this, we can use the border-collapse property:

.fahrvergnugen {
border-collapse: collapse;
}

.fahrvergnugen, .fahrvergnugen td {
border: 1px solid #000;
}

Output:

HTML table example with border-collapse

We can add padding to the <td> elements to make it look better:

.fahrvergnugen {
border-collapse: collapse;
}

.fahrvergnugen, .fahrvergnugen td {
border: 1px solid #000;
}

.fahrvergnugen td {
padding: 6px;
}

Output:

HTML table example with padding applied to td element

There are all kinds of styling options that can be applied to tables. Just think about what you have in your toolbox already: classes, background-colors, background-images, borders, and so much more. You have the knowledge to create some very attractive and professional tables of data right now. Explore your creative side and you might come up with something great!

Creating accessible, semantic tables

Beyond the basic table structure described above, there are other elements that may be used in the creation of tables. The <th> (table header) element is an essential part of most data tables.

<table class="fahrvergnugen">
<tr>
<th>Column 1 Heading</th>
<th>Column 2 Heading</th>
</tr>
<tr>
<td>Row 1 - Column 1 data</td>
<td>Row 1 - Column 2 data</td>
</tr>
<tr>
<td>Row 2 - Column 1 data</td>
<td>Row 2 - Column 2 data</td>
</tr>
</table>

Output:

HTML table with th elements

The <th> element attaches meaning to the structure of your data. It communicates to computer devices that the words inside the element describe the data in that column.

Grouping rows

You can attach more structure and meaning to your tables by adding <thead>, <tbody>, and <tfoot> elements.

If you use either the <thead> or <tfoot> elements, you should use the <tbody> element also.

<table class="fahrvergnugen">
<thead>
<tr>
<th>Column 1 Heading</th>
<th>Column 2 Heading</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row 1 - Column 1 data</td>
<td>Row 1 - Column 2 data</td>
</tr>
<tr>
<td>Row 2 - Column 1 data</td>
<td>Row 2 - Column 2 data</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="2">Footer Information</td>
</tr>
</tfoot>
</table>

Output:

HTML table example using thead, tbody, and tfoot

Colspan and rowspan

From the example above, you may have already guessed what the colspan attribute does. It extends the cell horizontally by the number of columns you specify as a value.

The colspan attribute may be applied to the <td> and <th> elements.

And rowspan extends the cell vertically by the number of rows specified in the rowspan attribute. For an example of using rowspan, see W3 Schools.

Tables and accessibility

Accessibility is the law of the land. It's important. So, make sure to pay close attention anytime you see the word "accessibility" in these lessons.

And you can use this WAVE evaluation tool to check your web pages for accessibility issues.

The courts have ruled that the Americans with Disabilities Act also applies to websites.

The federal government and your state government may also also have accessibility guidelines for certain types of websites.

But, in general, you should be fine if your website meets the AA level of the WCAG standards.

Many of the standards involve making sure that meaning can be extracted from your code programmatically, even if the user is unable to see the web page.

The <caption> element is one way that you can provide more meaning when creating tables. It should be used to provide a title for the table.

By default, the caption text will display above the table. But this can be changed using the caption-side CSS property.

<table class="fahrvergnugen">

<caption>Chicken Prices in Omaha</caption>

<thead>
<tr>
<th>Column 1 Heading</th>
<th>Column 2 Heading</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row 1 - Column 1 data</td>
<td>Row 1 - Column 2 data</td>
</tr>
<tr>
<td>Row 2 - Column 1 data</td>
<td>Row 2 - Column 2 data</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="2">Footer Information</td>
</tr>
</tfoot>
</table>
Describing tables

In some cases, it might be necessary to provide a description or summary of your table. This can help communicate information about your table to users, including those with visual impairments.

In prior versions of HTML, there was a summary attribute that was used for this purpose. However, this attribute has been deprecated.

You could provide a paragraph before the table for this purpose. Or you could provide this information in the caption element. See the Web Accessibility Initiative documentation for more information.

With all of that said, the best option is to create a simple and logical table that doesn't require an explanation.

Lists

Like tables, lists require more than one element. Fortunately, there are not as many elements as the table element. Only two elements are required.

Unordered List:

<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>

Output:

  • item 1
  • item 2
  • item 3

Ordered List:

<ol>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ol>

Output:

  1. item 1
  2. item 2
  3. item 3

Description List:

<dl>
<dt>Term 1</dt>
<dd>Description 1</dd>
<dt>Term 2</dt>
<dd>Description 2</dd>
</dl>

Output:

Term 1
Description 1
Term 2
Description 2

Nested lists

You can nest lists in order to create different levels in your list structure. For example:

<ul>
<li>item 1</li>
<li>item 2
<ul>
<li>item 2a</li>
<li>item 2b</li>
</ul>
</li>
<li>item 3</li>
</ul>

Output:

  • item 1
  • item 2
    • item 2a
    • item 2b
  • item 3

Notice that the nested <ul> is inside of a <li> element.

<ul>
<li>item 1</li>

<li>item 2
<ul>
<li>item 2a</li>
<li>item 2b</li>
</ul>
</li>

<li>item 3</li>
</ul>

The </li> tag must go after the </ul> tag:

<ul>
<li>item 1</li>
<li>item 2 <!-- Don't end the li here -->
<ul>
<li>item 2a</li>
<li>item 2b</li>
</ul>
</li> <!-- End it here -->
<li>item 3</li>
</ul>

The <ul> is a child of that <li> element. And the child must always end before the parent.

caution

If you do not format this correctly, you might get the following error message when checking HTML validation:

"Element ul not allowed as child of element ul in this context."

Styling lists

The list-style property is a shorthand property. It allows you to declare a string of values instead of using list-style-type, list-style-image, list-style-position, etc. See W3 Schools for more information.

ul {
list-style: circle;
}

Output:

Unordered list with circle list-style applied

note
list-style can also be applied to <li> elements.

And note that in most cases, you will need to be more specific with your selector. For examples, we could target unordered lists in the main content:

main ul {
list-style: circle;
}

Or you could add a class to the ul element and use a class selector in the CSS.

Image bullets

There are several ways to apply image bullets to your lists. A couple of options are the list-style-image and background-image properties.

list-style-image doesn't offer the designer much control over the position of the bullet. The bullet is automatically placed at the top left of the list item. Sometimes this doesn't line up right so you might want to use background-image instead.

In this case, it works using list-style-image.

ul {
list-style: url(images/green-bullet.png);
}

Output:

Unordered list with green bullets added using list-style CSS property

For a demonstration of using a CSS background-image for bullets, see this example.

Styling different levels of a list

We've talked about styling elements within elements. Lists are no different. You can use the structure of your HTML to style different levels in your lists.

<ul>
<li>item 1</li>
<li>item 2
<ul>
<li>item 2a</li>
<li>item 2b</li>
</ul>
</li>
<li>item 3</li>
</ul>

If I wanted to style the nested ul inside the parent ul, I could use this as a selector:

ul ul {
list-style: upper-alpha;
}

If I needed a more specific selector to target the li elements inside the nested ul, I could use:

ul ul li {
font-style: italic;
}

When using descendant selectors, we are going "deeper" into the HTML structure from left to right. In this case, we have a li inside of a ul that's inside of another ul. Take a look at the HTML code and make sure that you understand that contextual relationship.

Once again, you could be more specific with the selector, such as:

main ul ul li {
font-style: italic;
}

Or you could add a class to the parent ul and use something like:

.list-class ul li {
font-style: italic;
}

Also note that we have omitted one "level" in that hierarchy. The full "path" to the li elements inside the nested ul is:

<ul> => <li> => <ul> => <li>
<ul> <!-- 1 -->
<li>item 1</li>
<li>item 2 <!-- 2 -->
<ul> <!-- 3 -->
<li>item 2a</li>
<li>item 2b</li> <!-- 4 -->
</ul>
</li>
<li>item 3</li>
</ul>
  1. Everything is inside the parent ul element.
  2. Then a <li> element
  3. with a <ul> nested inside.
  4. And then we have <li> elements inside of that.

So, this selector also works for styling all of the li elements inside the nested ul:

ul li ul li {
font-style: italic;
}