HTML tables: the basics

html and css

This article shows you how HTML tables work.

We’ll cover the basics, such as rows, cells, headers, cells spanning multiple columns or rows, and how to group cells in a column for styling purposes.

Prerequisites:The basics of HTML
Objective:Get familiar with HTML tables.

Let’s start with the first fundamental question:

What is a table?

A table is a structured set of data (data table) presented in rows and columns. A table allows you to quickly and easily look up values that indicate some kind of connection between different types of data, for example: a person and their age, or a day of the week and the schedule.

Qu’est-ce qu’un tableau ?

How does a table work?

As we just said, a table is a set of rows and columns. The intersection of a row and a column is called a table cell.

What do we write inside the table?

To create a functional HTML table, we need to use at least 3 elements:

  • A table element that defines the table itself;
  • tr elements, standing for “table row”, which allow us to add rows and indicate the beginning and end of a table row;
  • td elements, standing for “table data”, which allow us to add cells in our rows and thus automatically create new columns. They indicate the beginning and end of a cell’s content.

The HTML table element represents the table itself. This element consists of an opening <table> and closing </table> tag pair within which we will place the other elements of our table.

<p>This is a paragraph before the table.</p>

<table>
   <!-- Here, we will write the table content -->
</table>

<p>This is a paragraph after the table.</p>

The tr and td elements are also represented as a pair of tags with their content between the tags.

In HTML, a table is built row by row. In each row (<tr>), we specify the content of the different cells (<td>).

For example, here is the code to create a table with two rows and three columns:

<table>
   <tr>
       <td>Alice</td>
       <td>33 years old</td>
       <td>France</td>
   </tr>
   <tr>
       <td>Sarah</td>
       <td>34 years old</td>
       <td>United States</td>
   </tr>
</table>
HTML tables: tr & td

Table styling

Looking at our table above, you’ll notice there are no borders. To fix this, we need to use the CSS border property. Here is the CSS code to add borders to our table:

td /* All table cells... */
{
    border: 1px solid black; /* will have a 1px border */
}
Table styling (HTML & CSS)

We’ve added borders, but they are separated from each other! There is space between the cells. To fix this, we’ll use the CSS border-collapse property which can take two values:

The border-collapse property is applied to the table element itself. It accepts two values:

  • collapse: borders will be merged together — this is the effect we want here;
  • separate: borders will be separated (default value).
table
{
    border-collapse: collapse; /* Table borders will be collapsed (cleaner look) */
}
td
{
    border: 1px solid black;
}
Table styling (HTML & CSS)

The header row

Now that we have what we wanted, let’s add the table header row. In the example below, the headers are “Name”, “Age”, and “Country”. The header row is created with a <tr> element, but instead of using <td> for cells, we use <th> (for “table header”).

<table>
    <tr>
        <th>Name</th>
        <th>Age</th>
        <th>Country</th>
    </tr>

    <tr>
        <td>Alice</td>
        <td>33 years old</td>
        <td>France</td>
    </tr>
    
    <tr>
        <td>Sarah</td>
        <td>34 years old</td>
        <td>United States</td>
    </tr>
</table>

The header row is very easy to recognize for two reasons:

  • the cells use <th> instead of the usual <td>;
  • it’s the first row of the table (it seems obvious, but it’s worth mentioning).

Since the header cells have a slightly different tag name, remember to update your CSS to apply borders to both regular cells and header cells (see the following figure).

table
{
    border-collapse: collapse;
}
td, th /* Add a border to td AND th elements */
{
    border: 1px solid black;
}
The header row

As you can see, your browser has bolded the header cell text. This is the default behavior of most browsers, but if you wish, you can change this with CSS.

Table caption

Normally, every table should have a caption. The caption quickly informs the visitor about the table’s content. Our example consists of a list of people, but what does it represent? Without a table caption, you’d see it just by looking at it, but it becomes clearer with a title.

To solve this problem, we can use <caption>.

This tag is placed at the very beginning of the table, just before the header. It contains the table’s caption (see the following figure):

<table> 
   <caption>Patients for coronavirus screening</caption>

   <tr>
       <th>Name</th>
       <th>Age</th>
       <th>Country</th>
   </tr>
   <tr>
       <td>Carmen</td>
       <td>33 years old</td>
       <td>Spain</td>
   </tr>
   <tr>
       <td>Michelle</td>
       <td>26 years old</td>
       <td>United States</td>
   </tr>
</table>
Table caption: the caption tag

This way, it’s much clearer.

Note that you can change the caption position with the CSS caption-side property, which can take two values:

  • top: the caption will be placed above the table (default);
  • bottom: the caption will be placed below the table.

We have just created our first complete HTML table above. Remember the syntax and especially the nesting order of elements, with our td elements inside our tr elements: we use a new td element each time we want to add a cell (and therefore a column) within the same row.

If you try to copy only the HTML code shown above and display it, you may get something that doesn’t look like what you’d expect from a table. This is perfectly normal since I have already applied some basic CSS styling to our first HTML table.

Remember that in HTML terms, even without CSS styling, the created object is indeed a table. Keep in mind that HTML’s role is only to structure content, meaning to make it understandable for browsers and search engines.

Also note that different browsers may display tables slightly differently by default. You’ll almost always need to add CSS to get the exact look you want.

To add a background color to our table cells, we’ll use the CSS background-color property. Let’s alternate colors between rows for better readability.

An HTML table
Un tableau HTML de 3 lignes avec une première ligne contenant 4 cellules, une deuxième ligne contenant seulement 2 cellules, et la dernière ligne contenant 3 cellules

To achieve this result, we can use the CSS :nth-child pseudo-class to target even or odd rows.

Here’s the CSS code for alternating row colors:

An HTML table

A structured table

We’ve learned how to build small, simple tables. These small tables are sufficient in most cases, but sometimes you’ll need to build larger, more complex tables.

We’ll discover two particular techniques:

  • For large tables, it is possible to divide them into three parts;
  • For some tables, you may need to merge cells together.

Splitting a large table

If your table is quite large, you’ll benefit from splitting it into several parts. There are HTML tags that allow you to define the three “zones” of a table:

  • the header (at the top): defined with the <thead></thead> tags;
  • the body (in the center): defined with the <tbody></tbody> tags;
  • the table footer (at the bottom): defined with the <tfoot></tfoot> tags.

What should go in the table footer? Generally, for long tables, you repeat the header cells there. This allows you to see, even at the bottom of the table, what each column refers to. Schematically, a three-part table is structured as shown in the following figure.

An HTML table with thead, tbody and tfoot

It’s a bit confusing, but it is recommended to write the tags in the following order:

  • <thead>: the header;
  • <tfoot>: the footer;
  • <tbody>: the body.

In the code, you specify the top part first, then the bottom part, and finally the main part (<tbody>). The browser will take care of displaying each element in the right place, so don’t worry.

Here is the code to build the table in three parts:

<!DOCTYPE html>

<html>
    <head>
        <title>Tables</title>
        <meta charset="utf-8">

        <style>
            table
            {
                border-collapse: collapse;
            }
            td, th /* Add a border to both td and th elements */
            {
                border: 1px solid black;
                padding: 10px;
            }
            caption {
                margin-top: 10px;
                margin-bottom: 10px;
            }
        </style>
    </head>

    <body>
        <table>
            <caption>Patients for coronavirus screening</caption>
            
            <thead>  <!-- Table header -->
                <tr>
                    <th>First Name</th>
                    <th>Age</th>
                    <th>Country</th>
                    <th>Email</th>
                </tr>
            </thead>

            <tfoot>
                <!-- Table footer -->
                <tr>
                    <th>First Name</th>
                    <th>Age</th>
                    <th>Country</th>
                    <th>Email</th>
                </tr>
            </tfoot>

            <tbody>
                <tr>
                    <td>Alice</td>
                    <td>33 years old</td>
                    <td>France</td>
                    <td>alice.hello@mymail.com</td>
                </tr>
                
                <tr>
                    <td>Leila</td>
                    <td>34 years old</td>
                    <td>United States</td>
                    <td>sarah.coco@mymail.com</td>
                </tr>

                <tr>
                    <td>Frank</td>
                    <td>43 years old</td>
                    <td>France</td>
                    <td>frank.doe@mymail.com</td>
                </tr>
                <tr>
                    <td>Martha</td>
                    <td>34 years old</td>
                    <td>France</td>
                    <td>fracois@supermail@com</td>
                </tr>
            </tbody>
        </table>
    </body>
</html>

It’s not mandatory to use all three tags (<thead>, <tbody>, <tfoot>). You might use only one or two of them. However, all three are recommended for better structure and accessibility.

If you use these tags, you can then style each section differently with CSS, for example giving the header and footer a different background color.

Spanning cells across multiple rows or columns

Sometimes, we want a cell to span multiple rows or columns. Take the following simple example, which shows common animal names. In some cases, we want to show the male and female names next to the generic animal name. Sometimes we don’t, and we want the generic animal name to span the entire width of the table.

The initial code looks like this:

<table>
  <tr>
    <th>Animals</th>
  </tr>
  <tr>
    <th>Hippopotamus</th>
  </tr>
  <tr>
    <th>Horse</th>
    <td>Mare</td>
  </tr>
  <tr>
    <td>Stallion</td>
  </tr>
  <tr>
    <th>Crocodile</th>
  </tr>
  <tr>
    <th>Chicken</th>
    <td>Rooster</td>
  </tr>
  <tr>
    <td>Rooster</td>
  </tr>
</table>

But the result doesn’t give us what we wanted:

Animals
Hippopotamus
HorseMare
Stallion
Crocodile
ChickenHen
Rooster

We need a way to span “Animals”, “Hippopotamus”, and “Crocodile” across two columns, and “Horse” and “Chicken” across two rows. Fortunately, table headers and cells have the colspan and rowspan attributes, which allow us to do just that. Both accept a unitless number value that equals the number of rows or columns to span.

For example, colspan="2" makes a cell span two columns:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Animals table</title>
    <link href="minimal-table.css" rel="stylesheet" type="text/css">
  </head>
  <body>
    <h1>Animals table</h1>

    <table>
      <tr>
        <th colspan="2">Animals</th>
      </tr>
      <tr>
        <th colspan="2">Hippopotamus</th>
      </tr>
      <tr>
        <th rowspan="2">Horse</th>
        <td>Mare</td>
      </tr>
      <tr>
        <td>Stallion</td>
      </tr>
      <tr>
        <th colspan="2">Crocodile</th>
      </tr>
      <tr>
        <th rowspan="2">Chicken</th>
        <td>Hen</td>
      </tr>
      <tr>
        <td>Rooster</td>
      </tr>
    </table>


  </body>
</html>

When NOT to use HTML tables

HTML tables should only be used for tabular data — that’s what they were designed for. Unfortunately, many people used HTML tables to lay out web pages, placing headers in one row, content in another, etc. This was common practice before CSS was widely supported.

In short, using tables for layout instead of CSS techniques is a bad idea. Here are the main reasons: table-based layouts reduce accessibility for visually impaired users, they produce messy code (“tag soup”), and tables are not automatically responsive.

  1. Les tableaux de mise en page diminuent l’accessibilité aux malvoyants : les lecteurs d’écran, utilisés par les non-voyants, interprètent les balises d’une page HTML et lisent à haute voix le contenu à l’utilisateur. Comme les tables ne sont pas le bon outil pour la mise en page et que le balisage est plus complexe qu’avec les techniques de mise en page des CSS, la sortie des lecteurs d’écran sera source de confusion pour leurs utilisateurs.
  2. Les tables produisent de la bouillie : Comme mentionné ci-dessus, les mises en page sur la base de tableaux comportent généralement des structures de balisage plus complexes que des techniques de mise en page appropriées. Le code résultant sera plus difficile à écrire, à maintenir et à déboguer.
  3. Les tableaux ne s’adaptent pas automatiquement : Si vous utilisez les propriétés de mise en page (<header>, <section>, <article> ou <div>), leur largeur est par défaut 100% de celle du parent. Par contre, les tableaux sont dimensionnés en fonction de leur contenu par défaut, de sorte que des mesures supplémentaires sont nécessaires pour que le style du tableau fonctionne effectivement sur les différents types d’écran.

There you go, now you can show off at parties…

We have some courses on sale at the Itamde web school: https://itamde.com/en/online-courses/

You can also find us on YouTube:

Ici => https://www.youtube.com/channel/UCZ4dhshzpVbbRPVuL9TNH4Q

Ou ici => https://www.youtube.com/channel/UCQlKs3ToaL8IKRbXtwtFnyA

Recent Posts

Recent Comments

Itamde is also an online programming school.

Itamde

Learn what you want, at your own pace

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

You may also be interested in…

Artificial intelligence is reshaping every pixel

Artificial intelligence is reshaping every pixel

Just a few years ago, editing a photo meant spending hours working meticulously in Photoshop, mastering layers, masks and curves. In 2026, everything has shifted. AI photo editing tools no longer settle for automatic filters — they understand image content, anticipate...

The 10 Best Free AI Tools for Developers in 2026

The 10 Best Free AI Tools for Developers in 2026

Artificial intelligence is transforming how developers write, test, and deploy code. In 2026, many AI tools are freely accessible, offering capabilities that would have seemed impossible just a few years ago. Whether you're a beginner or experienced developer, these...

CSS colors

CSS colors

CSS colors can be defined in hexadecimal. Hexadecimal uses three components: red, green, and blue. You can define colors in shorthand hexadecimal: for example #DC2 corresponds to #DDCC22. Note that some colors cannot be abbreviated. The goal is to shorten your...

Stay up to date with the latest news and developments

Access restricted content

Discover behind-the-scenes details of our projects, exclusive resources, and the progress of our creations in real time.

Sign up for our newsletter

Receive our news, creative insights, and updates from the studio directly in your inbox.

Follow us

Join our community on social media to follow our daily projects and interact with us.