Difficulty: Intermediate
The colspan and rowspan attributes allow a single table cell to stretch across multiple columns or rows, creating merged cells. This is essential for building complex table layouts such as schedules, reports with grouped headers, and invoices where certain labels span across several data columns or rows.
The colspan attribute specifies how many columns a cell should span horizontally. When you add colspan="3" to a <td> or <th>, that cell occupies the space of three normal cells. The remaining cells in that row must account for the extra width -- you need fewer cell elements in that row since the spanning cell absorbs the positions of the cells it covers.
The rowspan attribute works vertically, specifying how many rows a cell should span downward. When a cell has rowspan="2", it occupies its position in the current row and extends into the row below. The row below must therefore have one fewer cell element, since the spanning cell from above already fills that position. Getting rowspan arithmetic right is the most common source of table layout bugs.
You can combine colspan and rowspan on the same cell to create a cell that spans both horizontally and vertically. For example, a cell with colspan="2" rowspan="2" creates a block that covers a 2x2 area in the table grid. While powerful, complex spanning can make tables difficult to maintain and understand, so use it judiciously.
When working with spanning cells, the key rule is that the total number of column positions occupied in each row must be equal. Count normal cells as 1 and add colspan values for spanning cells. If a cell from a previous row spans into the current row via rowspan, that counts toward the current row's column total as well. Getting this arithmetic wrong is the leading cause of misaligned tables.
<table border="1">
<thead>
<tr>
<th rowspan="2">Name</th>
<th colspan="2">Contact</th>
<th colspan="2">Scores</th>
</tr>
<tr>
<th>Email</th>
<th>Phone</th>
<th>Math</th>
<th>Science</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice</td>
<td>alice@mail.com</td>
<td>555-0101</td>
<td>95</td>
<td>88</td>
</tr>
<tr>
<td>Bob</td>
<td>bob@mail.com</td>
<td>555-0202</td>
<td>82</td>
<td>91</td>
</tr>
</tbody>
</table>
This table uses a two-level header. The first header row has 'Name' spanning 2 rows vertically, and 'Contact' and 'Scores' each spanning 2 columns horizontally. The second header row provides the specific sub-headers. Notice the second <tr> in <thead> has only 4 <th> elements because the 'Name' cell from the first row already occupies the first column position.
<table border="1">
<thead>
<tr>
<th>Department</th>
<th>Employee</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="2">Engineering</td>
<td>Alice</td>
<td>Frontend Dev</td>
</tr>
<tr>
<td>Bob</td>
<td>Backend Dev</td>
</tr>
<tr>
<td rowspan="3">Marketing</td>
<td>Charlie</td>
<td>SEO Specialist</td>
</tr>
<tr>
<td>Diana</td>
<td>Content Writer</td>
</tr>
<tr>
<td>Eve</td>
<td>Social Media</td>
</tr>
</tbody>
</table>
The Department column uses rowspan to group employees by department. 'Engineering' spans 2 rows and 'Marketing' spans 3 rows. Each subsequent row in the group omits the department cell because the spanning cell already covers that column position.
<table border="1">
<thead>
<tr>
<th>Time</th>
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
</tr>
</thead>
<tbody>
<tr>
<td>9:00</td>
<td rowspan="2" colspan="2">Team Workshop</td>
<td>Standup</td>
</tr>
<tr>
<td>10:00</td>
<td>Code Review</td>
</tr>
<tr>
<td>11:00</td>
<td>Sprint Planning</td>
<td>Design Sync</td>
<td>1-on-1s</td>
</tr>
</tbody>
</table>
The 'Team Workshop' cell uses both rowspan="2" and colspan="2" to occupy a 2x2 block covering Monday and Tuesday for the 9:00 and 10:00 time slots. The adjacent rows have fewer cells to account for this block.
<table border="1">
<thead>
<tr>
<th>Item</th>
<th>Qty</th>
<th>Unit Price</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td>Notebook</td>
<td>3</td>
<td>$5.00</td>
<td>$15.00</td>
</tr>
<tr>
<td>Pen Set</td>
<td>2</td>
<td>$8.00</td>
<td>$16.00</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3"><strong>Grand Total</strong></td>
<td><strong>$31.00</strong></td>
</tr>
</tfoot>
</table>
A common invoice pattern: the footer row uses colspan="3" to merge the first three cells into one label area, leaving the last cell for the total amount.
colspan, rowspan, Complex Layouts, Merged Cells