π Lesson 7: Lists & Tables
Not everything belongs in a paragraph. When you're presenting a collection of items or comparing structured data, lists and tables are the right tools. They make content scannable, organized, and accessible.
π― Learning Objectives
By the end of this lesson, you will be able to:
- Create unordered lists with
<ul>and ordered lists with<ol> - Nest lists inside other lists for multi-level outlines
- Build definition lists with
<dl>,<dt>, and<dd> - Structure data tables with
<table>,<thead>,<tbody>, and related elements - Understand when to use a table versus when to use CSS layout
Estimated Time: 50 minutes
Hands-on: You'll build a recipes page with ingredient lists and a nutrition table.
π In This Lesson
Unordered Lists
An unordered list is a collection of items where the order doesn't matter β like a shopping list, a set of features, or a list of hobbies. Browsers display each item with a bullet point.
<ul>
<li>Flour</li>
<li>Sugar</li>
<li>Butter</li>
<li>Eggs</li>
</ul>
Two elements work together here:
<ul>β the unordered list container (wraps the entire list)<li>β each list item inside the container
β οΈ Important Rule
The only direct children of <ul> (or <ol>) should be <li> elements. Don't put <p>, <div>, or other elements directly inside the list wrapper β put them inside the <li> instead.
You can put almost anything inside an <li> β paragraphs, links, images, even other lists:
<ul>
<li>
<strong>Flour</strong> β all-purpose, 2 cups
</li>
<li>
<a href="https://example.com/butter">Butter</a> (unsalted)
</li>
</ul>
Ordered Lists
An ordered list is for items where sequence matters β step-by-step instructions, rankings, or numbered procedures. Browsers display each item with a number.
<ol>
<li>Preheat the oven to 350Β°F</li>
<li>Mix the dry ingredients</li>
<li>Add the wet ingredients</li>
<li>Pour into a greased pan</li>
<li>Bake for 25 minutes</li>
</ol>
The structure is identical to unordered lists β just swap <ul> for <ol>. The <li> elements are the same.
Customizing the Start Number
By default, ordered lists start at 1. You can change this with the start attribute:
<!-- Starts numbering at 5 -->
<ol start="5">
<li>Fifth item</li>
<li>Sixth item</li>
</ol>
You can also reverse the order with the reversed attribute (useful for countdowns or "top 10" lists):
<ol reversed>
<li>Third place</li>
<li>Second place</li>
<li>First place!</li>
</ol>
Unordered
β’ Bullets
β’ Order doesn't matter"] A --> C["<ol>
Ordered
1. Numbers
2. Sequence matters"] A --> D["<dl>
Definition
Term β Description"] B --> E["<li> items"] C --> F["<li> items"] D --> G["<dt> + <dd> pairs"] style A fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e293b style B fill:#f0fdf4,stroke:#22c55e,stroke-width:2px,color:#1e293b style C fill:#fdf4ff,stroke:#a855f7,stroke-width:2px,color:#1e293b style D fill:#fffbeb,stroke:#f59e0b,stroke-width:2px,color:#1e293b style E fill:#f8fafc,stroke:#64748b,stroke-width:1px,color:#1e293b style F fill:#f8fafc,stroke:#64748b,stroke-width:1px,color:#1e293b style G fill:#f8fafc,stroke:#64748b,stroke-width:1px,color:#1e293b
Nested Lists
You can put a list inside a list item to create multi-level outlines. This is called nesting:
<ul>
<li>Frontend
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
</li>
<li>Backend
<ul>
<li>Python</li>
<li>Node.js</li>
<li>Databases</li>
</ul>
</li>
</ul>
Notice that the nested <ul> goes inside the <li>, not after it. The browser automatically changes the bullet style for each level (disc β circle β square), though you can customize this with CSS.
You can also mix list types β an ordered list inside an unordered one, or vice versa:
<ol>
<li>Go to the grocery store
<ul>
<li>Milk</li>
<li>Bread</li>
<li>Eggs</li>
</ul>
</li>
<li>Come home and unpack</li>
<li>Start cooking dinner</li>
</ol>
π‘ Indentation Matters (for You)
HTML doesn't care about indentation β the browser ignores it. But you should care, because well-indented code makes nested structures like this much easier to read and debug. Use consistent indentation (4 spaces or 1 tab) for every level of nesting.
Definition Lists
A definition list is for term-description pairs β glossaries, FAQs, or any content where a label is paired with an explanation:
<dl>
<dt>HTML</dt>
<dd>HyperText Markup Language β the standard
language for creating web pages.</dd>
<dt>CSS</dt>
<dd>Cascading Style Sheets β a language for
describing how HTML elements look.</dd>
<dt>JavaScript</dt>
<dd>A programming language that makes web pages
interactive and dynamic.</dd>
</dl>
Three elements work together:
<dl>β the definition list wrapper<dt>β the definition term (the word or phrase being defined)<dd>β the definition description (the explanation)
A single term can have multiple descriptions, and a single description can apply to multiple terms:
<dl>
<!-- One term, multiple descriptions -->
<dt>HTML</dt>
<dd>A markup language for web content</dd>
<dd>First released in 1993 by Tim Berners-Lee</dd>
<!-- Multiple terms, one description -->
<dt>Frontend</dt>
<dt>Client-side</dt>
<dd>The part of a website that runs in the browser</dd>
</dl>
Definition lists are underused by beginners, but they're perfect for metadata displays, settings panels, FAQ pages, and glossaries.
Tables: The Basics
HTML tables display data in rows and columns β like a spreadsheet. Here's the simplest possible table:
<table>
<tr>
<td>Apple</td>
<td>Red</td>
<td>$1.20</td>
</tr>
<tr>
<td>Banana</td>
<td>Yellow</td>
<td>$0.50</td>
</tr>
</table>
The key elements:
<table>β the table container<tr>β a table row<td>β a table data cell (one piece of data)
Adding Header Cells
Use <th> instead of <td> for header cells. Browsers render them bold and centered by default, and screen readers use them to announce which column or row a data cell belongs to:
<table>
<tr>
<th>Fruit</th>
<th>Color</th>
<th>Price</th>
</tr>
<tr>
<td>Apple</td>
<td>Red</td>
<td>$1.20</td>
</tr>
<tr>
<td>Banana</td>
<td>Yellow</td>
<td>$0.50</td>
</tr>
</table>
π‘ <th> vs. <td>
Think of <th> as the label and <td> as the data. Just like headings versus paragraphs, the distinction is about meaning, not just appearance. Screen readers announce header cells differently so users can navigate large tables without getting lost.
Proper Table Structure
For better accessibility and styling control, wrap your rows in semantic sections:
<table>
<caption>Fruit Prices β Spring 2026</caption>
<thead>
<tr>
<th>Fruit</th>
<th>Color</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Apple</td>
<td>Red</td>
<td>$1.20</td>
</tr>
<tr>
<td>Banana</td>
<td>Yellow</td>
<td>$0.50</td>
</tr>
<tr>
<td>Cherry</td>
<td>Red</td>
<td>$3.00</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="2">Average</td>
<td>$1.57</td>
</tr>
</tfoot>
</table>
The additional elements:
<caption>β a visible title/description for the table (great for accessibility)<thead>β wraps the header row(s)<tbody>β wraps the data rows<tfoot>β wraps footer/summary rowscolspan="2"β makes a cell span across multiple columns
Table title"] A --> C["<thead>
Header rows"] A --> D["<tbody>
Data rows"] A --> E["<tfoot>
Footer rows"] C --> F["<tr> β <th> cells"] D --> G["<tr> β <td> cells"] E --> H["<tr> β <td> cells"] style A fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e293b style B fill:#fffbeb,stroke:#f59e0b,stroke-width:1px,color:#1e293b style C fill:#fdf4ff,stroke:#a855f7,stroke-width:2px,color:#1e293b style D fill:#f0fdf4,stroke:#22c55e,stroke-width:2px,color:#1e293b style E fill:#fef2f2,stroke:#ef4444,stroke-width:2px,color:#1e293b style F fill:#f8fafc,stroke:#64748b,stroke-width:1px,color:#1e293b style G fill:#f8fafc,stroke:#64748b,stroke-width:1px,color:#1e293b style H fill:#f8fafc,stroke:#64748b,stroke-width:1px,color:#1e293b
Spanning Rows and Columns
Sometimes a cell needs to stretch across multiple columns or rows:
<!-- Cell spans 2 columns -->
<td colspan="2">This cell is twice as wide</td>
<!-- Cell spans 3 rows -->
<td rowspan="3">This cell is three rows tall</td>
When a cell spans columns, remove the corresponding <td> cells from that row (since the spanning cell takes their place). The same logic applies to row spans β the rows below need one fewer cell.
Tables vs. Layout
β οΈ The Golden Rule of Tables
Use tables for tabular data only. Never use tables to control page layout (placing sidebars, navigation, footers, etc.). This was common in the late 1990s, but it's terrible for accessibility, mobile responsiveness, and maintenance. CSS Flexbox and Grid (which you'll learn in Modules 3β4) are the right tools for layout.
How do you know if your data belongs in a table? Ask yourself:
- Does the data have rows and columns that relate to each other?
- Would removing a column make the remaining data less meaningful?
- Could you describe it as a spreadsheet?
If you answered yes, it's tabular data β use a table. If the data is just items in a list or content sections on a page, use lists or semantic HTML elements instead.
| Use a Table For | Don't Use a Table For |
|---|---|
| Price comparisons | Page layout (header, sidebar, footer) |
| Schedules and timetables | Navigation menus |
| Sports statistics | Image galleries |
| Nutritional information | Form alignment |
Hands-on Exercise
ποΈ Exercise: Build a Recipe Page
Objective: Create a page that uses unordered lists, ordered lists, and a table.
Instructions:
- In your
my-websitefolder, create a new file calledrecipe.html - Use the Emmet shortcut to generate the HTML skeleton
- Set the
<title>to "My Favorite Recipe" - Add the following content inside
<body>:- An
<h1>with the recipe name - A short
<p>description - An
<h2>for "Ingredients" followed by a<ul>with at least 5 ingredients - An
<h2>for "Instructions" followed by an<ol>with at least 4 steps - An
<h2>for "Nutrition Facts" followed by a<table>with:- A
<caption> - A
<thead>with column headers (Nutrient, Amount) - A
<tbody>with at least 4 rows of data
- A
- An
- Add a link back to
index.html - Save and view with Live Server
π‘ Hint
Remember: <ul> for the ingredient list (order doesn't matter), <ol> for the instructions (order matters). For the table, don't forget to use <th> elements in the header row, not <td>.
β Example Solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Favorite Recipe</title>
</head>
<body>
<a href="index.html">Back to Home</a>
<h1>Classic Banana Pancakes</h1>
<p>Fluffy, golden pancakes made with ripe bananas.
Ready in under 20 minutes!</p>
<h2>Ingredients</h2>
<ul>
<li>2 ripe bananas</li>
<li>1 Β½ cups all-purpose flour</li>
<li>1 cup milk</li>
<li>1 egg</li>
<li>2 tablespoons sugar</li>
<li>1 teaspoon baking powder</li>
<li>Pinch of salt</li>
</ul>
<h2>Instructions</h2>
<ol>
<li>Mash the bananas in a large bowl</li>
<li>Add the egg, milk, and sugar; whisk together</li>
<li>Add the flour, baking powder, and salt; stir
until just combined (don't over-mix!)</li>
<li>Heat a non-stick pan over medium heat and add
a little butter</li>
<li>Pour ΒΌ cup of batter per pancake and cook until
bubbles form on top (about 2 minutes)</li>
<li>Flip and cook for 1 more minute</li>
<li>Serve with maple syrup and fresh fruit</li>
</ol>
<h2>Nutrition Facts</h2>
<table>
<caption>Per serving (2 pancakes)</caption>
<thead>
<tr>
<th>Nutrient</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<tr>
<td>Calories</td>
<td>320 kcal</td>
</tr>
<tr>
<td>Protein</td>
<td>8 g</td>
</tr>
<tr>
<td>Carbohydrates</td>
<td>52 g</td>
</tr>
<tr>
<td>Fat</td>
<td>9 g</td>
</tr>
</tbody>
</table>
</body>
</html>
π― Quick Quiz
Question 1: When should you use <ol> instead of <ul>?
Question 2: Where does a nested list go?
Question 3: What element provides a visible title for a table?
Question 4: Should you use a <table> to create a two-column page layout?
Summary
π Key Takeaways
<ul>creates an unordered (bulleted) list;<ol>creates an ordered (numbered) list- Both use
<li>for individual items β and<li>must be the direct child of a list element - Nest lists by placing a new
<ul>or<ol>inside an<li> <dl>,<dt>, and<dd>create definition lists for term-description pairs- Tables use
<table>,<tr>,<th>, and<td>β plus<thead>,<tbody>,<tfoot>, and<caption>for proper structure - Use
colspanandrowspanto span cells across multiple columns or rows - Tables are for data, not layout. CSS handles page layout.
π Your Project So Far
my-website/
βββ images/
β βββ sunset.jpg
βββ index.html
βββ about.html
βββ recipe.html β new in this lesson
π What's Next?
You now know how to present text, link pages, show images, and organize content with lists and tables. But most real websites also need to collect information from users β logins, search boxes, contact forms, surveys. In the next lesson, you'll learn how to build forms and input elements.