Creating HTML Tables

Tables are essential for displaying structured data on web pages. In this tutorial, you’ll learn how to create tables with headers, rows, and columns, and how to style them for better readability!

Why Use Tables?

Tables are perfect for displaying data that has a clear row-and-column structure, such as:

Important: Tables should be used for tabular data, not for page layout! Use CSS Grid or Flexbox for layout instead.

Basic Table Structure

Every HTML table is built from these essential elements:

Here’s the simplest possible table:

<table>
<tr>
  <td>Row 1, Cell 1</td>
  <td>Row 1, Cell 2</td>
</tr>
<tr>
  <td>Row 2, Cell 1</td>
  <td>Row 2, Cell 2</td>
</tr>
</table>

Your First Complete Table

Let’s build a table with headers and multiple rows:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Student Grades</title>
</head>
<body>
<h1>Class Grades</h1>
<table>
  <tr>
    <th>Student Name</th>
    <th>Subject</th>
    <th>Grade</th>
  </tr>
  <tr>
    <td>Sarah Johnson</td>
    <td>Math</td>
    <td>A</td>
  </tr>
  <tr>
    <td>Mike Chen</td>
    <td>Math</td>
    <td>B+</td>
  </tr>
  <tr>
    <td>Emma Davis</td>
    <td>Math</td>
    <td>A-</td>
  </tr>
</table>
</body>
</html>

How it works:

Table Sections: thead, tbody, and tfoot

For better organization and accessibility, divide your table into semantic sections:

<table>
<thead>
  <tr>
    <th>Product</th>
    <th>Price</th>
    <th>Stock</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td>Laptop</td>
    <td>$999</td>
    <td>15</td>
  </tr>
  <tr>
    <td>Mouse</td>
    <td>$25</td>
    <td>50</td>
  </tr>
  <tr>
    <td>Keyboard</td>
    <td>$75</td>
    <td>30</td>
  </tr>
</tbody>
<tfoot>
  <tr>
    <td>Total Items</td>
    <td></td>
    <td>95</td>
  </tr>
</tfoot>
</table>

Benefits:

Adding Basic Styling

Plain HTML tables look pretty bland. Let’s add some CSS to make them more readable:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Styled Table</title>
<style>
  table {
    width: 100%;
    border-collapse: collapse;
    margin: 20px 0;
  }

  th, td {
    padding: 12px;
    text-align: left;
    border: 1px solid #ddd;
  }

  th {
    background-color: #4CAF50;
    color: white;
    font-weight: bold;
  }

  tr:nth-child(even) {
    background-color: #f2f2f2;
  }

  tr:hover {
    background-color: #ddd;
  }
</style>
</head>
<body>
<h1>Product Inventory</h1>
<table>
  <thead>
    <tr>
      <th>Product</th>
      <th>Category</th>
      <th>Price</th>
      <th>In Stock</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Laptop</td>
      <td>Electronics</td>
      <td>$999</td>
      <td>Yes</td>
    </tr>
    <tr>
      <td>Desk Chair</td>
      <td>Furniture</td>
      <td>$299</td>
      <td>Yes</td>
    </tr>
    <tr>
      <td>Monitor</td>
      <td>Electronics</td>
      <td>$399</td>
      <td>No</td>
    </tr>
  </tbody>
</table>
</body>
</html>

Key styling concepts:

Column Spanning

Use colspan to make a cell span multiple columns:

<table>
<thead>
  <tr>
    <th colspan="3">Q1 Sales Report</th>
  </tr>
  <tr>
    <th>Month</th>
    <th>Sales</th>
    <th>Growth</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td>January</td>
    <td>$50,000</td>
    <td>5%</td>
  </tr>
  <tr>
    <td>February</td>
    <td>$55,000</td>
    <td>10%</td>
  </tr>
  <tr>
    <td>March</td>
    <td>$60,000</td>
    <td>9%</td>
  </tr>
</tbody>
</table>

The first header cell spans all 3 columns, creating a title row for the table.

Row Spanning

Use rowspan to make a cell span multiple rows:

<table>
<thead>
  <tr>
    <th>Department</th>
    <th>Employee</th>
    <th>Role</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td rowspan="2">Engineering</td>
    <td>Alice Smith</td>
    <td>Developer</td>
  </tr>
  <tr>
    <td>Bob Jones</td>
    <td>Designer</td>
  </tr>
  <tr>
    <td rowspan="2">Sales</td>
    <td>Carol White</td>
    <td>Account Manager</td>
  </tr>
  <tr>
    <td>David Brown</td>
    <td>Sales Rep</td>
  </tr>
</tbody>
</table>

The department names span two rows each, avoiding repetition.

Captions

Add a caption to describe your table:

<table>
<caption>Monthly Website Traffic - 2024</caption>
<thead>
  <tr>
    <th>Month</th>
    <th>Visitors</th>
    <th>Page Views</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td>January</td>
    <td>10,500</td>
    <td>25,000</td>
  </tr>
  <tr>
    <td>February</td>
    <td>12,300</td>
    <td>28,500</td>
  </tr>
</tbody>
</table>

The <caption> element provides a title that’s semantically associated with the table, which is excellent for accessibility!

Responsive Tables

Tables can be tricky on mobile devices. Here’s a simple responsive solution:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Responsive Table</title>
<style>
  .table-container {
    overflow-x: auto;
  }

  table {
    width: 100%;
    border-collapse: collapse;
    min-width: 500px;
  }

  th, td {
    padding: 12px;
    border: 1px solid #ddd;
    text-align: left;
  }

  th {
    background-color: #333;
    color: white;
  }
</style>
</head>
<body>
<h1>Responsive Product Table</h1>
<div class="table-container">
  <table>
    <thead>
      <tr>
        <th>Product</th>
        <th>Category</th>
        <th>Price</th>
        <th>Rating</th>
        <th>Stock</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Wireless Headphones</td>
        <td>Electronics</td>
        <td>$79.99</td>
        <td>4.5/5</td>
        <td>25</td>
      </tr>
      <tr>
        <td>Coffee Maker</td>
        <td>Appliances</td>
        <td>$49.99</td>
        <td>4.2/5</td>
        <td>15</td>
      </tr>
    </tbody>
  </table>
</div>
</body>
</html>

The overflow-x: auto allows the table to scroll horizontally on small screens instead of breaking the layout.

Scope Attribute for Accessibility

Use the scope attribute to help screen readers understand table structure:

<table>
<thead>
  <tr>
    <th scope="col">Name</th>
    <th scope="col">Age</th>
    <th scope="col">Country</th>
  </tr>
</thead>
<tbody>
  <tr>
    <th scope="row">Sarah</th>
    <td>28</td>
    <td>USA</td>
  </tr>
  <tr>
    <th scope="row">Ahmed</th>
    <td>35</td>
    <td>Egypt</td>
  </tr>
</tbody>
</table>

Common Mistakes to Avoid

Forgetting Table Rows

Problematic example:

<table>
  <td>Data 1</td>
  <td>Data 2</td>
</table>

Improved example:

<table>
  <tr>
    <td>Data 1</td>
    <td>Data 2</td>
  </tr>
</table>

Every cell must be inside a <tr> (table row)!

Using Tables for Layout

Problematic example:

<table>
  <tr>
    <td>Header</td>
  </tr>
  <tr>
    <td>Sidebar</td>
    <td>Main Content</td>
  </tr>
</table>

Improved example:

<header>Header</header>
<div class="container">
  <aside>Sidebar</aside>
  <main>Main Content</main>
</div>

Use CSS Grid or Flexbox for page layout, not tables!

Inconsistent Column Counts

Problematic example:

<table>
  <tr>
    <td>A</td>
    <td>B</td>
    <td>C</td>
  </tr>
  <tr>
    <td>D</td>
    <td>E</td>
  </tr>
</table>

Improved example:

<table>
  <tr>
    <td>A</td>
    <td>B</td>
    <td>C</td>
  </tr>
  <tr>
    <td>D</td>
    <td>E</td>
    <td>F</td>
  </tr>
</table>

Each row should have the same number of columns (unless using colspan/rowspan).

Try It Yourself

Ready to practice? Try these challenges:

Challenge 1: Simple Schedule (Basic)

Create a weekly class schedule table with:

Challenge 2: Product Comparison (Intermediate)

Build a product comparison table with:

Challenge 3: Complex Data Table (Advanced)

Create a financial report table with:

What You Learned

Congratulations! You now know:

Next Steps

Now that you can create tables, explore these related tutorials:

Want to experiment with tables? Try our interactive HTML editor!

Back to all tutorials