Table Element
The <thead> element defines a set of rows that represent the header of a table. It groups together one or more <tr> elements that contain <th> (header) cells, providing semantic meaning to the table structure. The <thead> helps browsers, screen readers, and other tools understand which rows contain column labels.
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Product Comparison</caption>
<thead>
<tr>
<th scope="col">Feature</th>
<th scope="col">Basic</th>
<th scope="col">Pro</th>
<th scope="col">Enterprise</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Storage</th>
<td>10 GB</td>
<td>100 GB</td>
<td>Unlimited</td>
</tr>
<tr>
<th scope="row">Users</th>
<td>1</td>
<td>10</td>
<td>Unlimited</td>
</tr>
<tr>
<th scope="row">Support</th>
<td>Email</td>
<td>Email + Chat</td>
<td>24/7 Phone</td>
</tr>
</tbody>
</table>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #ddd;
padding: 10px;
text-align: left;
}
thead {
background-color: #2c3e50;
color: white;
}
tbody th {
background-color: #ecf0f1;
}
</style>
< caption > Table caption </ caption >
< th scope = " col " > Header 1 </ th >
< th scope = " col " > Header 2 </ th >
< th scope = " col " > Header 3 </ th >
The <thead> element should appear in this order within a <table>:
<caption> (optional, but recommended)
<colgroup> (optional)
<thead> (optional)
<tbody> (one or more)
<tfoot> (optional)
The <thead> element supports all global HTML attributes .
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Employee Attendance - March 2024</caption>
<thead>
<tr>
<th scope="col">Employee</th>
<th scope="col">Department</th>
<th scope="col">Days Present</th>
<th scope="col">Days Absent</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice Johnson</td>
<td>Engineering</td>
<td>20</td>
<td>2</td>
</tr>
<tr>
<td>Bob Smith</td>
<td>Marketing</td>
<td>22</td>
<td>0</td>
</tr>
<tr>
<td>Carol White</td>
<td>Sales</td>
<td>21</td>
<td>1</td>
</tr>
</tbody>
</table>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
thead {
background-color: #4CAF50;
color: white;
font-weight: bold;
}
tbody tr:nth-child(even) {
background-color: #f2f2f2;
}
</style>
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Quarterly Sales Report</caption>
<thead>
<tr>
<th scope="col" rowspan="2">Region</th>
<th scope="colgroup" colspan="3">2024</th>
</tr>
<tr>
<th scope="col">Q1</th>
<th scope="col">Q2</th>
<th scope="col">Q3</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">North</th>
<td>$125K</td>
<td>$142K</td>
<td>$156K</td>
</tr>
<tr>
<th scope="row">South</th>
<td>$98K</td>
<td>$112K</td>
<td>$108K</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 {
background-color: #34495e;
color: white;
}
thead tr:last-child {
background-color: #7f8c8d;
color: white;
}
tbody th {
background-color: #ecf0f1;
text-align: left;
}
</style>
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Balance Sheet Summary</caption>
<thead>
<tr>
<th scope="col">Account</th>
<th scope="col">2023</th>
<th scope="col">2024</th>
<th scope="col">Change</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Assets</th>
<td>$1,250,000</td>
<td>$1,420,000</td>
<td class="positive">+13.6%</td>
</tr>
<tr>
<th scope="row">Liabilities</th>
<td>$450,000</td>
<td>$380,000</td>
<td class="negative">-15.6%</td>
</tr>
<tr>
<th scope="row">Equity</th>
<td>$800,000</td>
<td>$1,040,000</td>
<td class="positive">+30.0%</td>
</tr>
</tbody>
</table>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #ddd;
padding: 10px;
}
thead {
background-color: #2c3e50;
color: white;
}
tbody th {
background-color: #ecf0f1;
text-align: left;
}
td {
text-align: right;
}
.positive { color: #27ae60; font-weight: bold; }
.negative { color: #c0392b; font-weight: bold; }
</style>
Accessibility
Screen readers announce header cells differently, helping users navigate and understand table structure.
Printing
When printing long tables across multiple pages, browsers can repeat <thead> on each page.
Styling
Apply styles to all header rows at once with a single CSS selector.
Fixed Headers
Easily create sticky headers that remain visible while scrolling with position: sticky.
Semantic Structure
Clearly separates header content from data content, improving code maintainability.
JavaScript Selection
Easier to target and manipulate header rows with JavaScript using semantic selectors.
Interactive code playground requires JavaScript. Here's the code:
<table>
<thead>
<tr>
<th scope="col">Product</th>
<th scope="col">Price</th>
<th scope="col">Stock</th>
</tr>
</thead>
<tbody>
<tr>
<td>Laptop</td>
<td>$899</td>
<td>15</td>
</tr>
<tr>
<td>Mouse</td>
<td>$25</td>
<td>120</td>
</tr>
</tbody>
</table>
<style>
table {
border-collapse: collapse;
width: 100%;
}
/* Style all thead rows */
thead {
background-color: #3498db;
color: white;
font-size: 1.1em;
}
th, td {
border: 1px solid #ddd;
padding: 12px;
text-align: left;
}
</style>
Interactive code playground requires JavaScript. Here's the code:
<table>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Status</th>
<th scope="col">Progress</th>
</tr>
</thead>
<tbody>
<tr>
<td>Project Alpha</td>
<td>Active</td>
<td>75%</td>
</tr>
<tr>
<td>Project Beta</td>
<td>Planning</td>
<td>25%</td>
</tr>
</tbody>
</table>
<style>
table {
border-collapse: collapse;
width: 100%;
}
thead {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
th {
padding: 15px;
text-align: left;
font-weight: 600;
letter-spacing: 0.5px;
}
td {
padding: 12px;
border-bottom: 1px solid #e0e0e0;
}
</style>
Interactive code playground requires JavaScript. Here's the code:
<div class="table-container">
<table>
<thead>
<tr>
<th scope="col">Item</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr><td>Item 1</td><td>Description for item 1</td></tr>
<tr><td>Item 2</td><td>Description for item 2</td></tr>
<tr><td>Item 3</td><td>Description for item 3</td></tr>
<tr><td>Item 4</td><td>Description for item 4</td></tr>
<tr><td>Item 5</td><td>Description for item 5</td></tr>
<tr><td>Item 6</td><td>Description for item 6</td></tr>
<tr><td>Item 7</td><td>Description for item 7</td></tr>
<tr><td>Item 8</td><td>Description for item 8</td></tr>
</tbody>
</table>
</div>
<style>
.table-container {
max-height: 200px;
overflow-y: auto;
border: 1px solid #ddd;
}
table {
border-collapse: collapse;
width: 100%;
}
thead {
position: sticky;
top: 0;
background-color: #2c3e50;
color: white;
z-index: 10;
}
th, td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #ddd;
}
</style>
Always add the scope attribute to <th> elements in the <thead>:
< th scope = " col " > Column 1 </ th >
< th scope = " col " > Column 2 </ th >
< th scope = " col " > Column 3 </ th >
For multi-row headers, use rowspan and colspan with appropriate scope values:
< th scope = " col " rowspan = " 2 " > Product </ th >
< th scope = " colgroup " colspan = " 2 " > Pricing </ th >
< th scope = " col " > Regular </ th >
< th scope = " col " > Sale </ th >
When structured properly, screen readers will announce:
“Column header: Product Name”
“Column header: Price”
This helps users understand the table structure before navigating the data.
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Customer List (Click headers to sort)</caption>
<thead>
<tr>
<th scope="col" class="sortable">
Name <span class="sort-icon">⇅</span>
</th>
<th scope="col" class="sortable">
Email <span class="sort-icon">⇅</span>
</th>
<th scope="col" class="sortable">
Join Date <span class="sort-icon">⇅</span>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice Chen</td>
<td>alice@example.com</td>
<td>2024-01-15</td>
</tr>
<tr>
<td>Bob Martinez</td>
<td>bob@example.com</td>
<td>2024-02-20</td>
</tr>
</tbody>
</table>
<style>
table { border-collapse: collapse; width: 100%; }
thead { background-color: #34495e; color: white; }
th {
padding: 12px;
text-align: left;
cursor: pointer;
user-select: none;
}
th:hover { background-color: #4a5f7f; }
.sort-icon {
opacity: 0.5;
font-size: 0.8em;
margin-left: 5px;
}
td {
padding: 10px;
border-bottom: 1px solid #ddd;
}
</style>
Interactive code playground requires JavaScript. Here's the code:
<table>
<caption>Student Performance by Semester</caption>
<thead>
<tr>
<th scope="col" rowspan="2">Student</th>
<th scope="colgroup" colspan="2">Fall 2023</th>
<th scope="colgroup" colspan="2">Spring 2024</th>
</tr>
<tr>
<th scope="col">Midterm</th>
<th scope="col">Final</th>
<th scope="col">Midterm</th>
<th scope="col">Final</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Alex Kim</th>
<td>85</td>
<td>88</td>
<td>90</td>
<td>92</td>
</tr>
<tr>
<th scope="row">Jordan Lee</th>
<td>78</td>
<td>82</td>
<td>84</td>
<td>87</td>
</tr>
</tbody>
</table>
<style>
table { border-collapse: collapse; width: 100%; }
thead tr:first-child {
background-color: #2c3e50;
color: white;
}
thead tr:last-child {
background-color: #34495e;
color: white;
}
th, td {
border: 1px solid #ddd;
padding: 10px;
text-align: center;
}
tbody th {
background-color: #ecf0f1;
text-align: left;
}
</style>
/* Basic thead styling */
background : linear-gradient ( to right , # 667eea , # 764ba2 );
/* Fixed/sticky header */
box-shadow : 0 2 px 4 px rgba ( 0 , 0 , 0 , 0.1 );
/* Header hover effect */
/* Multi-row header differentiation */
background-color : # 2c3e50 ;
background-color : # 34495e ;
When tables span multiple pages during printing, the <thead> can automatically repeat on each page:
display : table-header-group ;
display : table-row-group ;
display : table-footer-group ;
✅ Always use <thead> for table headers
✅ Add scope attributes to all <th> elements
✅ Use semantic structure with <thead>, <tbody>, <tfoot>
✅ Keep headers descriptive but concise
✅ Use only <th> elements in <thead> (not <td>)
✅ Style consistently across your application
❌ Don’t use <td> in headers - use <th> instead
❌ Don’t skip <thead> even for simple tables
❌ Don’t forget scope attributes for accessibility
❌ Don’t make headers too wide - keep them scannable
❌ Don’t use deprecated attributes - use CSS instead
The <thead> 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)