Tables & Data

Table Structure (table, tr, td, th)

Master HTML tables for organizing tabular data. Learn table structure, semantic elements, and how to create accessible data tables.

When to Use Tables

Use Tables For:

  • Tabular data (spreadsheet-like)
  • Pricing comparisons
  • Schedules and calendars
  • Statistics and results
  • Data reports

Don't Use Tables For:

  • Page layout (use CSS Grid/Flexbox)
  • Navigation menus
  • Image galleries
  • Any non-tabular content

Basic Table Structure

html
<table>
    <tr>  <!-- Table Row --&gt;
        <th>Header 1</th>  <!-- Table Header --&gt;
        <th>Header 2</th>
        <th>Header 3</th>
    </tr>
    <tr>
        <td>Data 1</td>  <!-- Table Data --&gt;
        <td>Data 2</td>
        <td>Data 3</td>
    </tr>
    <tr>
        <td>Data 4</td>
        <td>Data 5</td>
        <td>Data 6</td>
    </tr>
</table>

Key Elements:

  • <table> - Container for the entire table
  • <tr> - Table row (horizontal)
  • <th> - Table header cell (bold, centered by default)
  • <td> - Table data cell

Complete Table Example

html
<table>
    <tr>
        <th>Name</th>
        <th>Age</th>
        <th>City</th>
    </tr>
    <tr>
        <td>John Doe</td>
        <td>28</td>
        <td>New York</td>
    </tr>
    <tr>
        <td>Jane Smith</td>
        <td>34</td>
        <td>Los Angeles</td>
    </tr>
    <tr>
        <td>Bob Johnson</td>
        <td>45</td>
        <td>Chicago</td>
    </tr>
</table>

Table Sections

Organize tables into semantic sections for better structure and styling:

html
<table>
    <thead>  <!-- Table Head --&gt;
        <tr>
            <th>Product</th>
            <th>Price</th>
            <th>Stock</th>
        </tr>
    </thead>
    
    <tbody>  <!-- Table Body --&gt;
        <tr>
            <td>Laptop</td>
            <td>$999</td>
            <td>15</td>
        </tr>
        <tr>
            <td>Mouse</td>
            <td>$25</td>
            <td>150</td>
        </tr>
        <tr>
            <td>Keyboard</td>
            <td>$75</td>
            <td>80</td>
        </tr>
    </tbody>
    
    <tfoot>  <!-- Table Footer --&gt;
        <tr>
            <th>Total Items</th>
            <td colspan="2">245</td>
        </tr>
    </tfoot>
</table>

Benefits of Sections:

  • Semantic structure for accessibility
  • Easier CSS targeting
  • Header/footer can repeat on printed pages
  • Better for screen readers

Table Caption

Provide a title/description for the table:

html
<table>
    <caption>Monthly Sales Report - Q4 2024</caption>
    <thead>
        <tr>
            <th>Month</th>
            <th>Sales</th>
            <th>Growth</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>October</td>
            <td>$45,000</td>
            <td>+12%</td>
        </tr>
        <tr>
            <td>November</td>
            <td>$52,000</td>
            <td>+15%</td>
        </tr>
        <tr>
            <td>December</td>
            <td>$68,000</td>
            <td>+31%</td>
        </tr>
    </tbody>
</table>

<!-- Caption styling --&gt;
<style>
caption {
    font-weight: bold;
    font-size: 1.2em;
    margin-bottom: 0.5em;
    caption-side: top; /* or bottom */
}
</style>

Table Headers (Scope)

Use scope attribute to clarify header relationships:

html
<table>
    <thead>
        <tr>
            <th scope="col">Product</th>
            <th scope="col">Q1</th>
            <th scope="col">Q2</th>
            <th scope="col">Q3</th>
            <th scope="col">Q4</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row">Laptops</th>
            <td>150</td>
            <td>180</td>
            <td>210</td>
            <td>190</td>
        </tr>
        <tr>
            <th scope="row">Tablets</th>
            <td>90</td>
            <td>95</td>
            <td>110</td>
            <td>105</td>
        </tr>
    </tbody>
</table>

<!-- scope values: --&gt;
<!-- col: Header for column --&gt;
<!-- row: Header for row --&gt;
<!-- colgroup: Header for group of columns --&gt;
<!-- rowgroup: Header for group of rows --&gt;

Styling Tables

Basic Styling

html
<style>
table {
    border-collapse: collapse; /* Removes space between borders */
    width: 100%;
    max-width: 800px;
    margin: 20px auto;
}

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

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

tr:nth-child(even) {
    background-color: #f2f2f2; /* Zebra striping */
}

tr:hover {
    background-color: #ddd; /* Highlight on hover */
}
</style>

Border Styles

css
/* Collapsed borders (default recommended) */
table {
    border-collapse: collapse;
}

/* Separated borders */
table {
    border-collapse: separate;
    border-spacing: 5px; /* Space between cells */
}

/* No borders */
table {
    border: none;
}
th, td {
    border: none;
}

/* Only horizontal borders */
th, td {
    border-top: 1px solid #ddd;
    border-bottom: 1px solid #ddd;
}

/* Only vertical borders */
th, td {
    border-left: 1px solid #ddd;
    border-right: 1px solid #ddd;
}

Responsive Tables

Method 1: Horizontal Scroll

html
<div class="table-container">
    <table>
        <!-- Table content --&gt;
    </table>
</div>

<style>
.table-container {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */
}

table {
    min-width: 600px; /* Minimum table width */
}
</style>

Method 2: Stacked on Mobile

html
<style>
@media screen and (max-width: 600px) {
    table, thead, tbody, th, td, tr {
        display: block;
    }
    
    thead tr {
        display: none; /* Hide header row */
    }
    
    tr {
        margin-bottom: 15px;
        border: 1px solid #ddd;
    }
    
    td {
        text-align: right;
        padding-left: 50%;
        position: relative;
    }
    
    td::before {
        content: attr(data-label);
        position: absolute;
        left: 10px;
        font-weight: bold;
    }
}
</style>

<table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Email</th>
            <th>Phone</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td data-label="Name">John Doe</td>
            <td data-label="Email">john@example.com</td>
            <td data-label="Phone">555-0100</td>
        </tr>
    </tbody>
</table>

Accessibility

Accessible Table Checklist:

  • Use <caption> for table title
  • Use <th> for headers (not <td>)
  • Add scope attribute to headers
  • Use <thead>, <tbody>, <tfoot>
  • Provide summary for complex tables
  • Ensure sufficient color contrast
  • Don't rely on color alone

Complex Table with IDs

html
<table>
    <caption>Sales by Region and Product</caption>
    <thead>
        <tr>
            <th id="region">Region</th>
            <th id="product">Product</th>
            <th id="sales">Sales</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td headers="region">North</td>
            <td headers="product">Laptops</td>
            <td headers="sales">$50,000</td>
        </tr>
    </tbody>
</table>

Best Practices

Do

  • Use tables for tabular data only
  • Include caption and headers
  • Use scope attribute
  • Use thead, tbody, tfoot
  • Make tables responsive
  • Style for readability
  • Test with screen readers
  • Use border-collapse: collapse

Don't

  • Use tables for layout
  • Forget accessibility
  • Make tables too wide
  • Use only for visual design
  • Forget mobile users
  • Use <td> for headers
  • Nest tables unnecessarily
  • Forget caption element

Complete Example

html
<table>
    <caption>Employee Directory - IT Department</caption>
    <thead>
        <tr>
            <th scope="col">Name</th>
            <th scope="col">Position</th>
            <th scope="col">Email</th>
            <th scope="col">Extension</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row">Alice Johnson</th>
            <td>Senior Developer</td>
            <td>alice@company.com</td>
            <td>x4501</td>
        </tr>
        <tr>
            <th scope="row">Bob Smith</th>
            <td>DevOps Engineer</td>
            <td>bob@company.com</td>
            <td>x4502</td>
        </tr>
        <tr>
            <th scope="row">Carol White</th>
            <td>QA Manager</td>
            <td>carol@company.com</td>
            <td>x4503</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <th scope="row" colspan="3">Total Employees</th>
            <td>3</td>
        </tr>
    </tfoot>
</table>

<style>
table {
    border-collapse: collapse;
    width: 100%;
    max-width: 900px;
    margin: 20px auto;
    font-family: Arial, sans-serif;
}

caption {
    font-size: 1.5em;
    font-weight: bold;
    margin-bottom: 10px;
    color: #333;
}

thead {
    background-color: #2c3e50;
    color: white;
}

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

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

tbody tr:hover {
    background-color: #e9ecef;
}

tfoot {
    font-weight: bold;
    background-color: #ecf0f1;
}

@media screen and (max-width: 600px) {
    table {
        font-size: 14px;
    }
    
    th, td {
        padding: 8px;
    }
}
</style>