HTML Colspan and Rowspan
So far, every cell in your tables has been the same size: one row tall and one column wide. Real data is not always so tidy. A heading might cover three months. A lunch break might stretch across every room. A "Total" label might need to sit under four columns at once.
For these cases, HTML lets one cell span across several columns or rows. Two attributes do the job: colspan (across columns) and rowspan (down rows). They are powerful, but they are also the most common source of broken tables, so the key is learning to count carefully. By the end of this lesson, you will.
What You Will Learnβ
- What
colspanandrowspando - How to count cells correctly when some span
- How to combine both in one table
- How to build grouped headers, schedules, and totals rows
- How to avoid the most common errors
- How to keep merged tables accessible
- When to split a table instead
In plain HTML, the attributes are written colspan and rowspan (all lowercase). This course page is written in MDX, so some live demos use the React-style spelling colSpan and rowSpan. Your HTML files should use the lowercase version, as in all the code tabs here.
colspan: Merge Across Columnsβ
colspan makes a cell stretch over several columns. Its value is a whole number: how many columns the cell covers.
- HTML Code
- Browser Output
<table>
<tr>
<th colspan="3">Quarterly sales</th>
</tr>
<tr>
<th>Jan</th>
<th>Feb</th>
<th>Mar</th>
</tr>
<tr>
<td>120</td>
<td>140</td>
<td>160</td>
</tr>
</table>
| Quarterly sales | ||
|---|---|---|
| Jan | Feb | Mar |
| 120 | 140 | 160 |
The first row has one cell, but it covers three columns. The table is three columns wide, and every row must add up to three.
The Counting Ruleβ
Each row must add up to the same number of columns. A cell with
colspan="3"counts as three.
| Row | Cells | Columns counted |
|---|---|---|
| 1 | one <th colspan="3"> | 3 |
| 2 | three <th> | 3 |
| 3 | three <td> | 3 |
All rows add up to 3, so the table is balanced.
rowspan: Merge Down Rowsβ
rowspan makes a cell stretch down over several rows. The value is how many rows the cell covers.
- HTML Code
- Browser Output
<table>
<tr>
<th>Day</th>
<th>Time</th>
<th>Session</th>
</tr>
<tr>
<td rowspan="2">Monday</td>
<td>09:00</td>
<td>HTML</td>
</tr>
<tr>
<td>11:00</td>
<td>CSS</td>
</tr>
<tr>
<td rowspan="2">Tuesday</td>
<td>09:00</td>
<td>JavaScript</td>
</tr>
<tr>
<td>11:00</td>
<td>Project</td>
</tr>
</table>
| Day | Time | Session |
|---|---|---|
| Monday | 09:00 | HTML |
| 11:00 | CSS | |
| Tuesday | 09:00 | JavaScript |
| 11:00 | Project |
Look closely at the code. "Monday" appears only once, in the first of its two rows. The second row (11:00, CSS) has only two cells, because the Monday cell from above is already occupying its first column.
The Counting Rule for Rowsβ
A cell with
rowspan="2"takes up a slot in the row below it too. In that next row, you write one cell fewer.
Here is how to picture it. Each X marks a slot occupied by a spanning cell above:
Row 1: [ Day ] [ Time ] [ Session ]
Row 2: [ Monday ] [ 09:00 ] [ HTML ]
Row 3: [ X ] [ 11:00 ] [ CSS ] β write only 2 cells here
Row 4: [ Tuesday] [ 09:00 ] [ JS ]
Row 5: [ X ] [ 11:00 ] [ Project ] β write only 2 cells here
Before you write a table with merged cells, sketch the grid on paper and mark which slots are covered. It takes one minute and prevents most mistakes.
Using Both Togetherβ
A single cell can have both attributes. It then covers a rectangle of cells.
- HTML Code
- Browser Output
<table>
<tr>
<td rowspan="2" colspan="2">Big block (2 Γ 2)</td>
<td>A</td>
</tr>
<tr>
<td>B</td>
</tr>
<tr>
<td>C</td>
<td>D</td>
<td>E</td>
</tr>
</table>
| Big block (2 Γ 2) | A | |
| B | ||
| C | D | E |
Count the slots:
| Row | What you write | Slots filled |
|---|---|---|
| 1 | Big block (takes 2 columns) + A | 2 + 1 = 3 |
| 2 | B (the big block covers the first 2 slots) | 2 (from above) + 1 = 3 |
| 3 | C, D, E | 3 |
Real-World Pattern 1: Grouped Headersβ
When several columns belong together, a heading above them makes the structure clear. This is the most common good use of colspan.
- HTML Code
- Browser Output
<table>
<caption>Exam results</caption>
<thead>
<tr>
<td rowspan="2"></td>
<th colspan="2" scope="colgroup">Math</th>
<th colspan="2" scope="colgroup">Science</th>
</tr>
<tr>
<th scope="col">Test 1</th>
<th scope="col">Test 2</th>
<th scope="col">Test 1</th>
<th scope="col">Test 2</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Aisha</th>
<td>92</td><td>88</td>
<td>85</td><td>90</td>
</tr>
<tr>
<th scope="row">Mateo</th>
<td>79</td><td>84</td>
<td>91</td><td>87</td>
</tr>
</tbody>
</table>
| Math | Science | |||
|---|---|---|---|---|
| Test 1 | Test 2 | Test 1 | Test 2 | |
| Aisha | 92 | 88 | 85 | 90 |
| Mateo | 79 | 84 | 91 | 87 |
Here, "Math" and "Science" each cover two columns (colspan="2"). The empty top-left cell covers two header rows (rowspan="2"). The attribute scope="colgroup" tells assistive technology that "Math" labels a group of columns.
Real-World Pattern 2: A Totals Rowβ
A label that spans all columns except the last is the classic invoice footer.
- HTML Code
- Browser Output
<tfoot>
<tr>
<th scope="row" colspan="3">Total</th>
<td>43.00</td>
</tr>
</tfoot>
| Notebook | 3 | 3.50 | 10.50 |
| Pen set | 2 | 16.25 | 32.50 |
| Total | 43.00 | ||
|---|---|---|---|
The first row of the table has four cells, so the footer must add up to four: 3 (from colspan) + 1 = 4.
Real-World Pattern 3: A Schedule with a Shared Breakβ
When an event covers every room or every day, one merged cell says it neatly.
- HTML Code
- Browser Output
<table>
<tr>
<th>Time</th>
<th>Room A</th>
<th>Room B</th>
</tr>
<tr>
<td>09:00</td>
<td>HTML basics</td>
<td>CSS basics</td>
</tr>
<tr>
<td>12:00</td>
<td colspan="2">Lunch (all rooms)</td>
</tr>
<tr>
<td>13:00</td>
<td>JavaScript</td>
<td>Accessibility</td>
</tr>
</table>
| Time | Room A | Room B |
|---|---|---|
| 09:00 | HTML basics | CSS basics |
| 12:00 | Lunch (all rooms) | |
| 13:00 | JavaScript | Accessibility |
Values and Limitsβ
| Attribute | Allowed values | Notes |
|---|---|---|
colspan | Whole numbers from 1 up to 1000 | Default is 1. Values over 1000 are treated as 1000 |
rowspan | Whole numbers from 0 up to 65534 | Default is 1. 0 means "to the end of the row group" |
rowspan="0" is a special value: the cell stretches down to the end of its <thead>, <tbody>, or <tfoot> section. Support varies, so most developers write the exact number instead.
Both attributes go only on <td> and <th>. They do nothing on <tr> or <table>.
What Happens When You Miscount?β
Too Many Cells in a Rowβ
If a row ends up wider than the others, the browser adds extra columns to the whole table, and the shape breaks.
<tr>
<th colspan="3">Title</th>
</tr>
<tr>
<td>A</td><td>B</td><td>C</td><td>D</td> <!-- 4 cells: one too many -->
</tr>
Too Few Cells in a Rowβ
If a row is short, you get a ragged right edge, with empty space where cells should be.
Overlapβ
A cell spanning down can collide with a cell you write in the next row, if you forget to remove one cell.
- Overlap (invalid)
- Fixed
<tr>
<td rowspan="2">Monday</td>
<td>09:00</td>
</tr>
<tr>
<td>Monday again</td> <!-- collides with the rowspan -->
<td>11:00</td>
</tr>
<tr>
<td rowspan="2">Monday</td>
<td>09:00</td>
</tr>
<tr>
<td>11:00</td> <!-- the Monday cell is already above -->
</tr>
Overlapping cells are a table-model error. Browsers try to recover, but the result is unpredictable. You can check for these errors in the browser's developer tools or in an HTML validator.
Accessibility: Use Merged Cells with Careβ
Merged cells make a table harder for assistive technology. A screen reader navigates a table as a grid, cell by cell. When cells span several slots, the grid is no longer regular, and it is easier for the user to get lost.
Follow these guidelines:
- Prefer simple tables. Use merging only when it clearly helps.
- Use
scopeon headings.scope="colgroup"for a heading over a column group,scope="col"for single columns, andscope="row"for row headers. - Keep headers consistent. Every data cell should still have a clear row and column heading.
- Avoid merged cells in the body of data tables where users compare values. Merge headings and summaries, not data.
- For very complex tables, use the
headersandidattributes to link cells to headings explicitly. You will see this in Table Accessibility. - Test with a screen reader.
In the schedule example, the lunch cell spans two rooms. That is fine for a simple table, but for a data table users may sort, filter, or navigate by cell, spanning data cells causes trouble. Think twice before merging cells that hold data, not labels.
When to Split a Table Insteadβ
If you find yourself writing a lot of colspan and rowspan, stop and ask whether two simple tables would be clearer.
| Instead of... | Consider... |
|---|---|
| One table with many merged group headings | Several tables, each with its own caption |
| A "table within a table" look | Separate tables or a list |
| Merged cells for visual style | CSS spacing and borders |
| A giant, irregular timetable | One table per day |
<h3>Monday</h3>
<table>
<caption>Monday sessions</caption>
...
</table>
<h3>Tuesday</h3>
<table>
<caption>Tuesday sessions</caption>
...
</table>
Simpler tables are easier to read, to style, to make responsive, and to listen to.
Global Audience Notesβ
- Keep merged headings short. A heading like "Q1" or "Math" is easy to translate and fits on small screens.
- Right-to-left pages reverse the column order.
colspanstill covers adjacent columns, so spanning keeps working. - State units once in a spanning heading (for example, "Sales (USD)" over several columns) instead of in every cell.
Common Mistakes to Avoidβ
- Rows that do not add up to the same number of columns.
- Forgetting to remove a cell in the row below a
rowspan. - Overlapping spans, where two cells fight for the same slot.
- Using
colspan="0". It is not valid. Use a positive number. - Merging cells just for looks when CSS would do.
- Merging data cells that users need to compare.
- Missing
scopeon headings above merged columns. - Putting
colspanon<tr>or<table>. It only works on cells. - Using huge span values instead of counting properly.
- Building a complicated table when two small ones would be clearer.
Practice Timeβ
Try these in your editor:
- Make a three-column table with a title row that covers all three columns.
- Make a table where one day name spans two time slots with
rowspan="2". - Draw a 3 Γ 3 grid on paper, mark a 2 Γ 2 merged block, then write the HTML.
- Build the "Exam results" table with grouped headers.
- Add a totals row that uses
colspanto span all but the last column. - Add a "Lunch" row that spans every room in a schedule.
- Break a table on purpose by adding one extra cell, and see what happens.
- Fix an overlap by removing the duplicated cell.
- Add
scope="colgroup"to a group heading. - Bonus: take your merged table and rewrite it as two simpler tables. Which is easier to read?
Quick Recapβ
Click a question to check your answer.
1. What do colspan and rowspan do?
colspan makes a cell stretch across several columns, and rowspan makes a cell stretch down several rows. The value is the number of columns or rows covered.
2. How do you count cells in a row that contains a colspan?
A cell with colspan="3" counts as three. Every row must add up to the same total number of columns.
3. What changes in the next row after a rowspan="2"?
The spanning cell already fills a slot in the next row, so you write one cell fewer in that row.
4. Can one cell have both colspan and rowspan?
Yes. It then covers a rectangle of slots, for example 2 columns wide by 2 rows tall.
5. Why should you be careful with merged cells?
They make the grid irregular, which can confuse screen reader users. Use them mainly for headings and summaries, add scope, and consider splitting complex tables.
Key Takeawaysβ
colspanmerges across columns androwspanmerges down rows. Both go on<td>or<th>.- Count slots, not cells: a spanning cell counts for every slot it covers, and every row must add up.
- After a
rowspan, write fewer cells in the rows below. - Good uses: grouped headers, totals rows, and shared breaks in a schedule.
- Keep merged tables as simple as possible, add
scope, and split a table when it gets complicated.
Merged cells change the column layout, which is also what you control with column groups. Learn how to style whole columns in Colgroup and Col, or return to the Tables overview.