Building Websites for Beginners: 7. Tables
Tags: beginners, html, webdev, tutorial
Published: 2020-12-23 10:19:59

# Tables
The next thing we are going to work on for our page is the details of our author's past employments. Before we start writing any HTML, however, we should take a brief moment to think about how it would be best to represent it. If you look at a typical CV, as well as the employer, they generally contain information about the job title, dates of employment, and a paragraph or two detailing what the job actually entailed. We could convey this by having the job titles or employers as some form of heading element, and any other information as paragraphs; but this would not properly express the fact that each of these fields are related to one another.

The perfect element to represent such 2-dimensional data is a table and, is often what is used on paper CVs as well. Tables in HTML, unfortunately, do how a small number of minor drawbacks, the main one being the difficulty of representing a two dimensional grid in a markup language. As a result of this, the markup for tables is probably the most complex of any element you will encounter when building websites. So instead of overwhelming you with the final code for the section as I have done previously, we will first learn about how to create tables in a series of smaller stages. This won't take long, I promise.

## Table rows and data
The first element we need to create a table is aptly named the `table`. This serves as the container for all of the data and indicates that anything inside of it is part of the table. The table contents are then split up into rows, represented by `tr` elements (which stand for table row). Each row then has it's cell data populated using `td` elements (which stand for table data). Confused? Let's look at an example:
```
<table>
    <tr>
        <td>Country</td>
        <td>Population</td>
        <td>Language</td>
    </tr>
    <tr>
        <td>UK</td>
        <td>63,182,000</td>
        <td>English</td>
    </tr>
    <tr>
        <td>France</td>
        <td>64,898,000</td>
        <td>Français</td>
    </tr>
    <tr>
        <td>Germany</td>
        <td>80,219,695</td>
        <td>Deutsch</td>
    </tr>
</table>
```
This represents a table with 4 rows and 3 columns. As you can see, each `tr` is a child of the `table`, and the `td` elements are children of the `tr` rows. When displayed on a page it will look like this:

<table>
    <tr>
        <td>Country</td>
        <td>Population</td>
        <td>Language</td>
    </tr>
    <tr>
        <td>UK</td>
        <td>63,182,000</td>
        <td>English</td>
    </tr>
    <tr>
        <td>France</td>
        <td>64,898,000</td>
        <td>Français</td>
    </tr>
    <tr>
        <td>Germany</td>
        <td>80,219,695</td>
        <td>Deutsch</td>
    </tr>
</table>

We do not explicitly declare columns in HTML, instead they are inferred from the number of cells in each row. This format can feel extremely unwieldy when you first encounter it but, as mentioned earlier, stems from the difficulty of trying to lay out a grid using markup. If we actually tried to lay out cells in the same way they appear, the browser would have to infer where columns started and ended, which might result in a different layout from what you intended. After you have worked on a few pages with tables you should get the hang of it and it will become second nature.

## Table Headings
We now have a basic table, but there is still some critical information missing. Someone looking at the table as rendered by the browser may well be able to guess that the top row represents the column headings, but the markup does not convey this; each row, has an identical structure. To remove this ambiguity we can use a `th` element with a `scope` attribute, instead of a `td`, for any headings. Which will make life easier for any machines or screen reader users reading our page. Have a look at the example below:
```
<table>
    <tr>
        <th scope="col">Country</th>
        <th scope="col">Population</th>
        <th scope="col">Language</th>
    </tr>
    <tr>
        <th scope="row">UK</th>
        <td>63,182,000</td>
        <td>English</td>
    </tr>
    <tr>
        <th scope="row">France</th>
        <td>64,898,000</td>
        <td>Français</td>
    </tr>
    <tr>
        <th scope="row">Germany</th>
        <td>80,219,695</td>
        <td>Deutsch</td>
    </tr>
</table>
```
What we have done here is to replace all of the `td` elements in the first row with `th` elements to define them as the headings for the table columns. The `scope` attribute must have a value of either `col` or `row` to define whether it is acting as a heading for a column or row.

We have also made the first cell in each of the other rows a heading; this shows that the population and language columns apply to the country, rather than, for example, the UK being the official country of the English language or Deutsch the official language of the number 80,219,695. This might seem unnecessary for people used to languages that read from left to right, as we assume that the first element we see is the most important, but again, this is just about being explicit.  When rendered by a browser our updated table will look like this:

<table>
    <tr>
        <th scope="col">Country</th>
        <th scope="col">Population</th>
        <th scope="col">Language</th>
    </tr>
    <tr>
        <th scope="row">UK</th>
        <td>63,182,000</td>
        <td>English</td>
    </tr>
    <tr>
        <th scope="row">France</th>
        <td>64,898,000</td>
        <td>Français</td>
    </tr>
    <tr>
        <th scope="row">Germany</th>
        <td>80,219,695</td>
        <td>Deutsch</td>
    </tr>
</table>

By default, browsers also render the text contained in any `th` elements in bold, which makes things more obvious for sighted users as well. A win-win situation.

## Table headers and bodies
There is one final change we are going to make to our example table before we get back to work on our CV page, which again will add a little clarity for anything reading the code. The first row of our table is now composed entirely of `th` elements, but otherwise looks structurally similar to the other rows. To further differentiate it's component parts, we can split the table into a header and body.

To do this we wrap the first row with the column headings into a `thead` element and the rest of the rows into a `tbody` as below:
```
<table>
    <thead>
        <tr>
            <th scope="col">Country</th>
            <th scope="col">Population</th>
            <th scope="col">Language</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row">UK</th>
            <td>63,182,000</td>
            <td>English</td>
        </tr>
        <tr>
            <th scope="row">France</th>
            <td>64,898,000</td>
            <td>Français</td>
        </tr>
        <tr>
            <th scope="row">Germany</th>
            <td>80,219,695</td>
            <td>Deutsch</td>
        </tr>
    </tbody>
</table>
```
This won't change how the browser renders the table at all, it just helps us organise the data and provides further clues as to the meaning of the contents. There is also a `tfoot` to define a footer for a table, but this is less frequently seen. An example of it's use would be the totals row for a financial spreadsheet.

## The CV Section
Now we have covered the syntax for building tables in HTML, we can finally add the next section to our page. Copy and paste the following lines between the end of the last `section` element, and the ending `main` tag.
```
    </section>
…
    <section>
        <h2>My greatest achievements</h2>
        <table>
            <thead>
                <tr>
                    <th scope="col">Position</th>
                    <th scope="col">Employer</th>
                    <th scope="col">Description</th>
                    <th scope="col">Date</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <th scope="row">Job 1</th>
                    <td>Employer 1</td>
                    <td>Vestibulum vel feugiat nisl, quis consequat odio. Vestibulum tempus venenatis risus a
                        faucibus.
                        Donec a mi finibus, laoreet nisl eget, ultricies tortor.</td>
                    <td>2015 - 2020</td>
                </tr>
                <tr>
                    <th scope="row">Job 2</th>
                    <td>Employer 2</td>
                    <td>Aliquam id sem ante. Morbi eget laoreet est. Donec ut est dapibus, mattis nisl ut,
                        accumsan
                        odio.</td>
                    <td>2014 - 2015</td>
                </tr>
                <tr>
                    <th scope="row">Job 3</th>
                    <td>Employer 3</td>
                    <td>Aenean vitae vestibulum nulla. Quisque purus dui, bibendum nec ex molestie, egestas
                        semper
                        dui.
                        In auctor blandit odio at tincidunt.</td>
                    <td>2012 - 2014</td>
                </tr>
                <tr>
                    <th scope="row">Job 4</th>
                    <td>Employer 4</td>
                    <td>Morbi neque odio, scelerisque in molestie non, vestibulum at ante. Sed sagittis dui at
                        nulla
                        consequat dignissim. Cras convallis aliquam tellus, ac sagittis nisi porttitor ut. Proin
                        lorem
                        augue, feugiat et magna vel, mattis egestas mi.</td>
                    <td>2011</td>
                </tr>
            </tbody>
        </table>
    </section>
…
</main>
```
All of these elements should now be familiar to you. We have added a new `section` with a `h2` and `table` as children. The `table` has a `thead` and `tbody` and all of the `th` elements have the appropriate `scope` attributes.

## Wrapping up

Now that our page is starting to get a little longer, instead of showing the complete code for the page, I will just provide a link to the [final index.html for this chapter](https://github.com/BezPowell/building_websites_for_beginners/blob/master/code/s1c7/index.html).

I have talked a lot in this chapter about how we can use specific elements to give added meaning to our content. While many of the changes I made to the table will make no visual difference, and may seem unnecessary at first, you must remember that about 99.9% of the time your HTML files will be read by a computer, rather than a person.

While people are generally flexible and good at inferring meaning from context, machines (unfortunately) are invariably stubbornly inflexible and pendantic; and as our pages must first be processed by machines before anyone can view them, it is in our best interests to be as explicit with our code as we can. Also, if you come back to try and make changes to your pages months or years after initially making them, your future self will thank you if they are as clear and unambiguous as possible.

In the next chapter we will cover how to add links to pages and go over the difference between block and inline elements.

---
This is a chapter from my <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License</a> book, Building Websites for Beginners. You can read everything that I have written so far on the [book website](https://bezpowell.github.io/building_websites_for_beginners/), and can see the [source code on github](https://github.com/BezPowell/building_websites_for_beginners).