HTML Tables
HTML tables display tabular data in rows and columns. Proper table structure with semantic elements ensures accessibility and makes data easier to understand.
Basic Table Structure
Tables use <table> as the container, <tr> for table rows, <th> for header cells, and <td> for data cells. Each row contains the same number of cells for proper alignment.
Table headers (<th>) should be used for row and column labels. They're bold and centered by default, and screen readers identify them as headers, helping users understand data relationships.
The scope attribute on <th> specifies whether the header applies to a row (scope='row') or column (scope='col'). This is crucial for accessibility.
<!-- Basic table -->
<table>
<tr>
<th scope="col">Name</th>
<th scope="col">Age</th>
<th scope="col">City</th>
</tr>
<tr>
<td>John Doe</td>
<td>30</td>
<td>New York</td>
</tr>
<tr>
<td>Jane Smith</td>
<td>25</td>
<td>Los Angeles</td>
</tr>
<tr>
<td>Bob Johnson</td>
<td>35</td>
<td>Chicago</td>
</tr>
</table>
Table Sections
Use <thead> for header rows, <tbody> for body rows, and <tfoot> for footer rows. These semantic elements improve accessibility and allow separate styling. Browsers can repeat thead and tfoot when printing multi-page tables.
The thead typically contains column headers. The tbody contains the main data. The tfoot can contain summaries, totals, or notes.
These sections aren't required but are strongly recommended for accessibility and code organization. They make tables easier to style and maintain.
<!-- Table with sections -->
<table>
<thead>
<tr>
<th scope="col">Product</th>
<th scope="col">Quantity</th>
<th scope="col">Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Widget A</td>
<td>10</td>
<td>$50.00</td>
</tr>
<tr>
<td>Widget B</td>
<td>5</td>
<td>$75.00</td>
</tr>
<tr>
<td>Widget C</td>
<td>8</td>
<td>$60.00</td>
</tr>
</tbody>
<tfoot>
<tr>
<th scope="row">Total</th>
<td>23</td>
<td>$185.00</td>
</tr>
</tfoot>
</table>
Spanning Rows and Columns
The colspan attribute makes a cell span multiple columns. colspan='2' means the cell takes up two column spaces. Use it for headers that apply to multiple columns or merged cells.
The rowspan attribute makes a cell span multiple rows. rowspan='3' means the cell takes up three row spaces. Use it for labels that apply to multiple rows.
When using colspan or rowspan, reduce the number of cells in affected rows/columns accordingly. The total cells per row must remain consistent.
<!-- Column spanning -->
<table>
<tr>
<th colspan="2" scope="col">Name</th>
<th scope="col">Age</th>
</tr>
<tr>
<th scope="col">First</th>
<th scope="col">Last</th>
<th scope="col"></th>
</tr>
<tr>
<td>John</td>
<td>Doe</td>
<td>30</td>
</tr>
</table>
<!-- Row spanning -->
<table>
<tr>
<th rowspan="2" scope="row">Contact</th>
<td>Email: john@example.com</td>
</tr>
<tr>
<td>Phone: (123) 456-7890</td>
</tr>
</table>
<!-- Complex spanning -->
<table>
<tr>
<th rowspan="2" scope="col">Name</th>
<th colspan="2" scope="col">Contact</th>
</tr>
<tr>
<th scope="col">Email</th>
<th scope="col">Phone</th>
</tr>
<tr>
<td>John Doe</td>
<td>john@example.com</td>
<td>(123) 456-7890</td>
</tr>
</table>
Table Caption and Summary
The <caption> element provides a title or description for the table. It must be the first child of <table>. Captions help all users understand the table's purpose and are especially important for accessibility.
For complex tables, consider adding an id to the table and a description in a separate paragraph, linked with aria-describedby. This provides more detailed context for screen reader users.
Never use tables for layout—use CSS Grid or Flexbox instead. Tables are for tabular data only. Using tables for layout causes serious accessibility problems.
<!-- Table with caption -->
<table>
<caption>Monthly Sales Report - Q1 2025</caption>
<thead>
<tr>
<th scope="col">Month</th>
<th scope="col">Sales</th>
<th scope="col">Growth</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">January</th>
<td>$50,000</td>
<td>+5%</td>
</tr>
<tr>
<th scope="row">February</th>
<td>$55,000</td>
<td>+10%</td>
</tr>
<tr>
<th scope="row">March</th>
<td>$60,000</td>
<td>+9%</td>
</tr>
</tbody>
</table>
<!-- Complex table with aria-describedby -->
<p id="table-description">
This table shows quarterly revenue broken down by product category
and region, with year-over-year comparisons.
</p>
<table aria-describedby="table-description">
<caption>Q1 2025 Revenue by Category and Region</caption>
<!-- table content -->
</table>
Styling Tables with CSS
Use CSS to style tables—avoid deprecated HTML attributes like border, cellpadding, and cellspacing. CSS provides more control and separates presentation from content.
Common table styles include borders (border-collapse, border), cell padding (padding on td/th), alternating row colors (nth-child), and hover effects. These improve readability.
Make tables responsive with CSS. Options include horizontal scrolling (overflow-x: auto), stacked layouts on mobile (display: block), or hiding less important columns at small sizes.
<!-- HTML table -->
<table class="styled-table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr>
<td>John Doe</td>
<td>john@example.com</td>
<td>Developer</td>
</tr>
<tr>
<td>Jane Smith</td>
<td>jane@example.com</td>
<td>Designer</td>
</tr>
</tbody>
</table>
<!-- CSS styling -->
<style>
.styled-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
font-size: 16px;
}
.styled-table thead tr {
background-color: #2c3e50;
color: white;
text-align: left;
}
.styled-table th,
.styled-table td {
padding: 12px 15px;
border: 1px solid #ddd;
}
.styled-table tbody tr {
border-bottom: 1px solid #ddd;
}
.styled-table tbody tr:nth-child(even) {
background-color: #f3f3f3;
}
.styled-table tbody tr:hover {
background-color: #f1f1f1;
}
/* Responsive table */
@media screen and (max-width: 600px) {
.styled-table {
display: block;
overflow-x: auto;
}
}
</style>