Table Element
The <th> element defines a header cell in a table. Header cells label rows or columns and provide crucial context for understanding the data in <td> cells. The <th> element is essential for creating accessible tables, as it helps screen readers associate data with its corresponding labels.
Critical for Accessibility
Always use <th> for header cells instead of <td>. Screen readers rely on <th> elements to properly announce table structure and data relationships.
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Team Performance - Q1 2024</caption>
<thead>
<tr>
<th scope="col">Team Member</th>
<th scope="col">Tasks Completed</th>
<th scope="col">Quality Score</th>
<th scope="col">Rating</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Alice Johnson</th>
<td>42</td>
<td>9.2/10</td>
<td>Excellent</td>
</tr>
<tr>
<th scope="row">Bob Martinez</th>
<td>38</td>
<td>8.8/10</td>
<td>Very Good</td>
</tr>
<tr>
<th scope="row">Carol Davis</th>
<td>45</td>
<td>9.5/10</td>
<td>Outstanding</td>
</tr>
</tbody>
</table>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #ddd;
padding: 10px;
text-align: left;
}
thead th {
background-color: #2c3e50;
color: white;
font-weight: bold;
}
tbody th {
background-color: #ecf0f1;
font-weight: 600;
}
tbody td {
text-align: center;
}
</style>
< th scope = " col " > Column Name </ th >
< th scope = " row " > Row Name </ th >
<!-- Header for column group -->
< th scope = " colgroup " > Group Name </ th >
<!-- Header for row group -->
< th scope = " rowgroup " > Group Name </ th >
The scope attribute specifies whether the header cell applies to a column, row, or group. This is the most important attribute for accessibility.
scope="col" - Header for a column
< th scope = " col " > Name </ th >
scope="row" - Header for a row
< th scope = " row " > John Doe </ th >
scope="colgroup" - Header for a group of columns
< th scope = " colgroup " colspan = " 2 " > Personal Info </ th >
scope="rowgroup" - Header for a group of rows
< th scope = " rowgroup " rowspan = " 3 " > Department A </ th >
These attributes allow header cells to span multiple columns or rows:
colspan - Number of columns the header spans
rowspan - Number of rows the header spans
For complex tables, the headers attribute explicitly associates data cells with header cells using IDs.
Provides an abbreviated version of the header content for screen readers:
< th abbr = " Temp " > Temperature (°C) </ th >
The <th> element supports all global HTML attributes .
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Product Inventory</caption>
<thead>
<tr>
<th scope="col">Product ID</th>
<th scope="col">Name</th>
<th scope="col">Quantity</th>
<th scope="col">Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>P001</td>
<td>Laptop</td>
<td>15</td>
<td>$899</td>
</tr>
<tr>
<td>P002</td>
<td>Mouse</td>
<td>120</td>
<td>$25</td>
</tr>
<tr>
<td>P003</td>
<td>Keyboard</td>
<td>45</td>
<td>$75</td>
</tr>
</tbody>
</table>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #ddd;
padding: 10px;
text-align: left;
}
thead th {
background-color: #3498db;
color: white;
}
tbody tr:hover {
background-color: #f0f8ff;
}
</style>
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Monthly Website Statistics</caption>
<thead>
<tr>
<th scope="col">Metric</th>
<th scope="col">January</th>
<th scope="col">February</th>
<th scope="col">March</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Page Views</th>
<td>45,200</td>
<td>48,300</td>
<td>52,100</td>
</tr>
<tr>
<th scope="row">Unique Visitors</th>
<td>12,400</td>
<td>13,200</td>
<td>14,800</td>
</tr>
<tr>
<th scope="row">Bounce Rate</th>
<td>32%</td>
<td>29%</td>
<td>27%</td>
</tr>
</tbody>
</table>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #ddd;
padding: 10px;
}
thead th {
background-color: #16a085;
color: white;
}
tbody th {
background-color: #ecf0f1;
text-align: left;
}
tbody td {
text-align: right;
}
</style>
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Exam Scores by Subject</caption>
<thead>
<tr>
<th scope="col">Student</th>
<th scope="col">Math</th>
<th scope="col">Science</th>
<th scope="col">English</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Alice</th>
<td>92</td>
<td>88</td>
<td>95</td>
</tr>
<tr>
<th scope="row">Bob</th>
<td>85</td>
<td>91</td>
<td>82</td>
</tr>
<tr>
<th scope="row">Carol</th>
<td>94</td>
<td>89</td>
<td>93</td>
</tr>
</tbody>
</table>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #ddd;
padding: 10px;
}
thead th {
background-color: #e74c3c;
color: white;
text-align: center;
}
tbody th {
background-color: #fadbd8;
text-align: left;
}
tbody td {
text-align: center;
}
</style>
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Sales Report - 2024</caption>
<thead>
<tr>
<th scope="col" rowspan="2">Region</th>
<th scope="colgroup" colspan="2">Q1</th>
<th scope="colgroup" colspan="2">Q2</th>
</tr>
<tr>
<th scope="col">Target</th>
<th scope="col">Actual</th>
<th scope="col">Target</th>
<th scope="col">Actual</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">North</th>
<td>$100K</td>
<td>$125K</td>
<td>$110K</td>
<td>$142K</td>
</tr>
<tr>
<th scope="row">South</th>
<td>$90K</td>
<td>$98K</td>
<td>$95K</td>
<td>$112K</td>
</tr>
</tbody>
</table>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #ddd;
padding: 10px;
text-align: center;
}
thead tr:first-child th {
background-color: #2c3e50;
color: white;
}
thead tr:last-child th {
background-color: #34495e;
color: white;
}
tbody th {
background-color: #ecf0f1;
text-align: left;
}
</style>
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Department Structure</caption>
<thead>
<tr>
<th scope="col">Department</th>
<th scope="col">Team</th>
<th scope="col">Members</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="rowgroup" rowspan="2">Engineering</th>
<th scope="row">Backend</th>
<td>8</td>
</tr>
<tr>
<th scope="row">Frontend</th>
<td>6</td>
</tr>
<tr>
<th scope="rowgroup" rowspan="2">Marketing</th>
<th scope="row">Content</th>
<td>4</td>
</tr>
<tr>
<th scope="row">Social Media</th>
<td>3</td>
</tr>
</tbody>
</table>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #ddd;
padding: 10px;
text-align: left;
}
thead th {
background-color: #8e44ad;
color: white;
}
tbody th[scope="rowgroup"] {
background-color: #d7bde2;
font-weight: bold;
}
tbody th[scope="row"] {
background-color: #f4ecf7;
}
td {
text-align: center;
}
</style>
For tables where scope isn’t sufficient, use the headers attribute:
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Student Performance by Subject and Term</caption>
<thead>
<tr>
<th id="student" scope="col">Student</th>
<th id="math-fall" scope="col">Math (Fall)</th>
<th id="math-spring" scope="col">Math (Spring)</th>
<th id="eng-fall" scope="col">English (Fall)</th>
<th id="eng-spring" scope="col">English (Spring)</th>
</tr>
</thead>
<tbody>
<tr>
<th id="alice" scope="row">Alice</th>
<td headers="alice math-fall">85</td>
<td headers="alice math-spring">92</td>
<td headers="alice eng-fall">88</td>
<td headers="alice eng-spring">91</td>
</tr>
<tr>
<th id="bob" scope="row">Bob</th>
<td headers="bob math-fall">78</td>
<td headers="bob math-spring">82</td>
<td headers="bob eng-fall">85</td>
<td headers="bob eng-spring">87</td>
</tr>
</tbody>
</table>
<style>
table {
border-collapse: collapse;
width: 100%;
font-size: 0.9em;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
}
thead th {
background-color: #27ae60;
color: white;
text-align: center;
}
tbody th {
background-color: #d5f4e6;
text-align: left;
}
tbody td {
text-align: center;
}
</style>
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Styled Header Examples</caption>
<thead>
<tr>
<th scope="col" class="header-primary">Primary</th>
<th scope="col" class="header-success">Success</th>
<th scope="col" class="header-warning">Warning</th>
<th scope="col" class="header-danger">Danger</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data 1</td>
<td>Data 2</td>
<td>Data 3</td>
<td>Data 4</td>
</tr>
</tbody>
</table>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
padding: 12px;
text-align: center;
border: 1px solid #ddd;
}
.header-primary {
background-color: #3498db;
color: white;
}
.header-success {
background-color: #27ae60;
color: white;
}
.header-warning {
background-color: #f39c12;
color: white;
}
.header-danger {
background-color: #e74c3c;
color: white;
}
</style>
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Sortable Table (Click headers)</caption>
<thead>
<tr>
<th scope="col" class="sortable">
Name <span class="sort-indicator">↕</span>
</th>
<th scope="col" class="sortable">
Age <span class="sort-indicator">↕</span>
</th>
<th scope="col" class="sortable">
Score <span class="sort-indicator">↕</span>
</th>
</tr>
</thead>
<tbody>
<tr><td>Alice</td><td>28</td><td>92</td></tr>
<tr><td>Bob</td><td>34</td><td>85</td></tr>
<tr><td>Carol</td><td>25</td><td>95</td></tr>
</tbody>
</table>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
padding: 10px;
text-align: left;
border: 1px solid #ddd;
}
.sortable {
cursor: pointer;
user-select: none;
background-color: #34495e;
color: white;
position: relative;
}
.sortable:hover {
background-color: #4a5f7f;
}
.sort-indicator {
position: absolute;
right: 10px;
opacity: 0.6;
font-size: 0.8em;
}
td {
text-align: center;
}
</style>
< th scope = " col " > Name </ th >
< td >< strong > January </ strong ></ td >
< th scope = " row " > January </ th >
When properly marked up with <th> and scope, screen readers announce:
Column header : “Name, column header”
Row header : “January, row header”
Data cell : “January, $10,000”
Without proper markup, screen readers would just say “$10,000” with no context.
/* Basic header styling */
background-color : # 2c3e50 ;
background-color : # 34495e ;
background-color : # ecf0f1 ;
background-color : # 4a5f7f ;
/* Headers with borders */
border : 2 px solid # 34495e ;
border-bottom : 3 px solid # 2c3e50 ;
Always Use scope
Every <th> should have a scope attribute (col, row, colgroup, or rowgroup).
Use for Both Axes
Use <th> for column headers AND row headers, not just columns.
Provide Abbreviations
Use the abbr attribute for long header text to improve screen reader experience.
Keep Text Concise
Header text should be short and descriptive. Avoid full sentences.
Visual Distinction
Style headers differently from data cells (bold, background color, etc.).
Test with Screen Readers
Always test complex tables with actual screen reader software.
< td >< strong > Product Name </ strong ></ td >
< td >< strong > Price </ strong ></ td >
< th scope = " col " > Product Name </ th >
< th scope = " col " > Price </ th >
< th scope = " col " > Name </ th >
<!-- ❌ Bad: using th for regular data -->
<!-- ✅ Good: only first cell is a header -->
< th scope = " row " > Product A </ th >
The <th> element is supported in all browsers:
✅ Chrome (all versions)
✅ Firefox (all versions)
✅ Safari (all versions)
✅ Edge (all versions)
✅ Opera (all versions)
✅ Internet Explorer (all versions)
The scope and headers attributes are also universally supported.