Advertisement
🌐 Core Elements

HTML Tables – Structured Tabular Data

HTML tables are designed for one purpose: displaying tabular data β€” information that has a natural row-and-column structure, like a spreadsheet, timetable, or comparison chart. Modern HTML provides a rich set of elements (thead, tbody, tfoot, caption, th with scope) that make tables both well-structured and accessible.

⏱️ 14 min read🎯 BeginnerπŸ“… Updated 2026

Basic Table: table, tr, td

The three core table elements are:

  • <table> β€” the wrapper element for the entire table
  • <tr> β€” a table row
  • <td> β€” a table data cell (standard cell)
HTML
<table>
  <tr>
    <td>HTML</td>
    <td>Structure</td>
    <td>Beginner</td>
  </tr>
  <tr>
    <td>CSS</td>
    <td>Styling</td>
    <td>Beginner</td>
  </tr>
  <tr>
    <td>JavaScript</td>
    <td>Interactivity</td>
    <td>Intermediate</td>
  </tr>
</table>
Result: A 3Γ—3 grid of cells. By default the browser renders tables with no borders β€” you need CSS to add visible borders.

Table Headers – th and scope

The <th> element defines a header cell. Unlike <td>, a <th> is bold and centred by default, and it carries semantic meaning β€” it labels a column or row.

The scope attribute tells screen readers whether the header applies to a column (scope="col") or a row (scope="row").

HTML
<table>
  <tr>
    <th scope="col">Language</th>
    <th scope="col">Purpose</th>
    <th scope="col">Level</th>
  </tr>
  <tr>
    <td>HTML</td>
    <td>Structure</td>
    <td>Beginner</td>
  </tr>
  <tr>
    <td>CSS</td>
    <td>Styling</td>
    <td>Beginner</td>
  </tr>
</table>

Table Structure: thead, tbody, tfoot

For any table beyond the simplest, wrap your rows in the semantic section elements:

  • <thead> β€” the header section (column labels)
  • <tbody> β€” the body (data rows)
  • <tfoot> β€” the footer (totals, notes)

These elements don't change visual rendering by default, but they allow browsers to keep the header and footer visible when the table body scrolls, and they help screen readers and CSS target sections independently.

HTML
<table>
  <thead>
    <tr>
      <th scope="col">Course</th>
      <th scope="col">Lessons</th>
      <th scope="col">Duration</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>HTML Fundamentals</td>
      <td>24</td>
      <td>3 hours</td>
    </tr>
    <tr>
      <td>CSS Basics</td>
      <td>30</td>
      <td>4 hours</td>
    </tr>
    <tr>
      <td>JavaScript Essentials</td>
      <td>45</td>
      <td>6 hours</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <td><strong>Total</strong></td>
      <td><strong>99</strong></td>
      <td><strong>13 hours</strong></td>
    </tr>
  </tfoot>
</table>

The caption Element

The <caption> element provides a visible title for a table. It must be the first child of <table>. Both sighted users and screen readers benefit from a clear caption β€” it explains what the table is about without relying on surrounding text.

HTML
<table>
  <caption>ylearner Course Catalogue – 2026</caption>
  <thead>
    <tr>
      <th scope="col">Course</th>
      <th scope="col">Level</th>
      <th scope="col">Free?</th>
    </tr>
  </thead>
  <tbody>
    <tr><td>HTML</td><td>Beginner</td><td>Yes</td></tr>
    <tr><td>Python</td><td>Beginner</td><td>Yes</td></tr>
    <tr><td>JavaScript</td><td>Intermediate</td><td>Yes</td></tr>
  </tbody>
</table>
Advertisement

colspan and rowspan – Merging Cells

Use colspan to make a cell span multiple columns, and rowspan to make a cell span multiple rows.

HTML
<!-- colspan: cell spans 2 columns -->
<table>
  <caption>Weekly Schedule</caption>
  <thead>
    <tr>
      <th scope="col">Time</th>
      <th scope="col">Monday</th>
      <th scope="col">Tuesday</th>
      <th scope="col">Wednesday</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">9:00 AM</th>
      <td colspan="2">HTML Workshop (spans Mon + Tue)</td>
      <td>CSS Intro</td>
    </tr>
    <tr>
      <th scope="row">11:00 AM</th>
      <td>JS Basics</td>
      <td rowspan="2">Project Work (spans 11 AM + 1 PM)</td>
      <td>Python Intro</td>
    </tr>
    <tr>
      <th scope="row">1:00 PM</th>
      <td>Review</td>
      <td>Git Basics</td>
    </tr>
  </tbody>
</table>
When using colspan / rowspan: count your cells carefully. If a row should have 3 cells but one cell has colspan="2", that row only needs 2 <td> elements total. A cell count mismatch causes columns to misalign.

Use Tables for Data Only

Tables are NOT for layout. In the 1990s developers used tables to position page columns. This practice is obsolete β€” use CSS Flexbox or Grid for layout. Table misuse causes serious accessibility problems because screen readers announce cell relationships that don't exist. Only use <table> when the content is genuinely tabular (it has meaningful rows AND meaningful columns).

Good use cases for tables:

  • Comparison charts (features vs. pricing tiers)
  • Timetables and schedules
  • Sports results / league tables
  • Financial data and reports
  • Specification sheets

Accessibility Best Practices

An accessible table communicates the relationship between each data cell and its header. Key practices:

  • Always use <th> for header cells β€” never style a <td> to look like a header.
  • Add scope="col" on column headers and scope="row" on row headers.
  • Use <caption> to give the table a descriptive title.
  • For complex tables with multiple header rows, use the headers attribute on data cells to point to the relevant header cell IDs.
HTML
<!-- Fully accessible table with id/headers association -->
<table>
  <caption>Course pricing by plan</caption>
  <thead>
    <tr>
      <th id="course" scope="col">Course</th>
      <th id="free" scope="col">Free Plan</th>
      <th id="pro" scope="col">Pro Plan</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th id="html-row" scope="row">HTML</th>
      <td headers="free html-row">All lessons</td>
      <td headers="pro html-row">All lessons + projects</td>
    </tr>
    <tr>
      <th id="py-row" scope="row">Python</th>
      <td headers="free py-row">First 10 lessons</td>
      <td headers="pro py-row">Full course + mentoring</td>
    </tr>
  </tbody>
</table>

Tables Are for Data β€” Structure Them So Everyone Can Read

A table is for tabular data (rows Γ— columns of related values), not for page layout β€” use CSS Grid/Flexbox for layout. A properly built table also stays understandable to screen-reader users, who navigate cell by cell.

<table>
  <caption>Q1 Sales by Region</caption>
  <thead>
    <tr><th scope="col">Region</th><th scope="col">Sales</th></tr>
  </thead>
  <tbody>
    <tr><th scope="row">North</th><td>$12,000</td></tr>
  </tbody>
</table>
πŸ”
Why scope and <caption> matter

scope="col"/scope="row" tells assistive tech which header describes a cell, so "$12,000" is announced as "North, Sales, $12,000" instead of a lone number. <caption> gives the whole table a title. These cost nothing visually and make data tables genuinely accessible.

πŸ‹οΈ Practical Exercise

  1. Create a table with two columns and two rows.
  2. Add a header row using <th>.
  3. Group the header in <thead> and the body in <tbody>.
  4. Merge two cells using colspan.
  5. Add a <caption> describing the table.

πŸ”₯ Challenge Exercise

Build a pricing table with three plans (columns) and four features (rows), using <thead> for the plan names and <tbody> for features. Use colspan for a "Most Popular" banner row across all columns, and add a <caption>. Confirm headers use <th> rather than bold text.

πŸ“‹ Summary

  • Core elements: <table>, <tr>, <td> (data cell), <th> (header cell).
  • Semantic structure: <thead>, <tbody>, <tfoot> divide the table into logical sections.
  • <caption> gives the table a visible, accessible title β€” always include one.
  • colspan merges cells horizontally; rowspan merges cells vertically.
  • Use scope="col" / scope="row" on <th> elements for screen reader accessibility.
  • Tables are for tabular data only β€” never use them for page layout.

Interview Questions

  • What are the core elements used to build an HTML table?
  • What is the difference between <th> and <td>?
  • What do <thead>, <tbody>, and <tfoot> provide?
  • What do colspan and rowspan do?
  • Why should tables be used for tabular data and not page layout?

FAQ

Do I need thead and tbody on every table? +

Technically no β€” they are optional. But using them is considered best practice. They improve code readability, enable independent CSS styling of sections, and help browsers handle long tables in print or overflow scenarios (some browsers keep <thead> visible at the top of each printed page).

How do I add borders to an HTML table? +

Use CSS. The old HTML border attribute is deprecated. A modern approach:

CSS
table {
  border-collapse: collapse; /* Remove double borders */
  width: 100%;
}

th, td {
  border: 1px solid #dee2e6;
  padding: 0.5rem 0.75rem;
  text-align: left;
}

thead tr {
  background-color: #f8f9fa;
}
Can I make a table responsive? +

Yes. Wrap the <table> in a <div> with overflow-x: auto β€” this lets the table scroll horizontally on small screens without breaking the page layout. For complex tables, consider a mobile-specific CSS approach that reformats rows as stacked cards on narrow screens.

What is the difference between td and th? +

<td> is a standard data cell β€” it holds the actual data values. <th> is a header cell β€” it labels a row or column. Browsers render <th> bold and centred by default, but more importantly, screen readers announce it as a header, giving users context for the data cells it governs.