—HTML Series · Post 12: HTML Tables
HTML Tables:
Data, Not Layout
Tables got a bad reputation because the old web used them for page layout. But for actual data — schedules, comparisons, pricing — they're exactly the right tool.
If you've ever looked at a spreadsheet, a comparison chart, a class schedule, or a pricing grid — you've looked at tabular data. And in HTML, the way you present tabular data is with a <table>.
But there's a history lesson here that matters: in the early web (late 90s, early 2000s), developers used tables to build entire page layouts. Navigation bars, sidebars, footers — all crammed into table rows and cells. It was a hack. It was messy. And when CSS came along and gave us Flexbox and Grid, the web moved on.
So now "tables are bad" became a common take. But that's wrong. Tables for layout are bad. Tables for data are exactly right. Let's learn how to build them properly.
Table Structure — The Hierarchy
A well-structured HTML table isn't just rows and cells thrown together. It has a clear hierarchy, and each piece serves a purpose — both visually and for accessibility. Here's how the pieces fit together:
<thead>, <tbody>, and <tfoot> aren't just for organization — they're semantic. Screen readers use them to help users navigate the table. The browser can also use them to keep the header visible while scrolling a long table. Always include them.
Building Your First Table
Let's build a real table — a course schedule for CodeHerWay. We'll use every structural element:
| Week | Topic | Project | Difficulty |
|---|---|---|---|
| 1 | HTML Foundations | Personal Bio Page | Beginner |
| 2 | CSS Styling | Styled Portfolio | Beginner |
| 3 | JavaScript Basics | Interactive Quiz | Intermediate |
| 4 | React Intro | Component Library | Intermediate |
| Total: 4 weeks · 4 projects | |||
Every row is a <tr>. Every header cell is a <th>. Every data cell is a <td>. And the <caption> tells everyone (including screen readers) what this table is about.
<th> vs <td> — Headers vs Data
This is a distinction beginners often skip. They put everything in <td> cells and call it done. But <th> exists for a reason:
<th> cells are header cells. Browsers automatically bold them. Screen readers announce them as headers and use them to describe each column to the user. They're not just styled differently — they carry semantic meaning that says "this cell describes the cells below it."
Headers aren't just for columns. If the first cell in each row acts as a label for that row (like a person's name in a roster), use <th scope="row">. The scope attribute tells assistive tech exactly what the header describes — "col" for column headers, "row" for row headers.
Merging Cells — colspan & rowspan
Sometimes a cell needs to stretch across multiple columns or multiple rows. That's what colspan and rowspan are for.
| Feature | Free | Pro ($9/mo) |
|---|---|---|
| HTML Course | ✅ | ✅ |
| JavaScript Course | ❌ | ✅ |
| AI Code Mentor | ❌ | ✅ |
| Start free. Upgrade when you're ready. | ||
colspan="3" makes that footer cell stretch across all three columns. rowspan works the same way but vertically — a cell stretches down across multiple rows. You'll use colspan far more often than rowspan, but both exist when you need them.
When to Use Tables (and When NOT To)
This is the most important section of this post. The answer is simple, but people still get it wrong:
Ask yourself: "Would this data make sense in a spreadsheet?" If the answer is yes — rows of data with consistent columns — use a table. If the answer is no, use CSS layout instead. It's that simple.
I avoided tables for months because I kept seeing "don't use tables" in every tutorial. I thought they were deprecated or something. So when I needed to display a comparison chart, I built it with a grid of divs. Thirty-two divs. For a 4×8 data grid.
Then someone looked at my code and said, "Why didn't you just use a table?"
I didn't have an answer. Tables aren't bad. Using them for layout is bad. For actual tabular data, they're the right tool. I rewrote it in five minutes and it was cleaner, more accessible, and half the code. 🤦♀️
Don't Forget <caption>
The <caption> element is the table's title. It goes directly inside the <table> tag, before <thead>. Most developers skip it, but it's important for accessibility — screen readers announce the caption so users know what the table is about before they start navigating it.
Captions render above the table by default. If you want it below, use caption-side: bottom in CSS. You can style it however you want — but don't remove it. Even if you visually hide it, keep it in the HTML for screen readers.
🔨 Mini Build: Coding Bootcamp Comparison
Build a comparison table for three coding bootcamps (real or fictional):
The Bottom Line
HTML tables are simple once you understand the hierarchy: <table> wraps everything, <thead>/<tbody>/<tfoot> provide structure, <tr> creates rows, <th> marks headers, and <td> holds the data.
Use <caption> to title your tables. Use colspan and rowspan when cells need to span. And always, always remember: tables are for data, not layout. If it belongs in a spreadsheet, use a table. If it doesn't, use CSS.
Tables have a reputation problem they don't deserve. Use them correctly, and they're one of the cleanest, most accessible structures in HTML.
That's 12 posts deep into HTML fundamentals. You've covered document structure, text, links, lists, images, forms, tables, accessibility, semantic elements, and more. You're not just learning HTML — you're building a real foundation. Keep going.