👀 Live Preview
Cell in column 2 spans two rows with rowspan="2":
| Row 1, Cell 1 | Row 1–2, Cell 2 (rowspan=2) | Row 1, Cell 3 |
| Row 2, Cell 1 | Row 2, Cell 3 | |
| Row 3, Cell 1 | Row 3, Cell 2 | Row 3, Cell 3 |

The rowspan attribute lets a single table cell span multiple rows vertically. Use it on <td> or <th> when one label or value should cover several rows — like a category name beside multiple data rows, or a sidebar header in a timetable. Set a positive integer (e.g. rowspan="2"), then omit the matching cell in the rows below. In JavaScript, use cell.rowSpan (capital S). Not the same as rows on <textarea>.
Span 2, 3, or more.
Where it applies.
1 or greater.
Vertical vs horizontal.
DOM property.
Textarea differs.
rowspan AttributeThe primary purpose of rowspan is to control the vertical layout of tables by letting one cell cover multiple rows. This helps group related data under a single label and reduces repeated text in the first column.
For example, a product table might list three sizes under one “T-Shirt” cell with rowspan="3", instead of writing “T-Shirt” three times.
rowspan merges cells vertically across rows. colspan merges cells horizontally across columns. You can use both on the same cell when needed.
Add rowspan to a <td> or <th> with a positive integer:
<td rowspan="2">Spans two rows</td>
<th rowspan="3">Category</th><td> and <th> inside a <table>.rowspan="1" (single row, no merge).cellElement.rowSpan = 3 (capital S).<textarea> — use rows for textarea height.The rowspan attribute accepts a positive integer — the number of rows the cell should span:
rowspan="1" — Default; single row (no merge).rowspan="2" — Cell covers two adjacent rows.rowspan="3" — Common for category labels spanning three data rows.<tr>
<th rowspan="3">Electronics</th>
<td>Phone</td>
<td>$499</td>
</tr>
<tr>
<!-- no cell in column 1 — covered by rowspan -->
<td>Tablet</td>
<td>$299</td>
</tr>
<tr>
<td>Laptop</td>
<td>$899</td>
</tr>With rowspan="3", the first cell stretches down three rows. Rows 2 and 3 omit a cell in that column because the slot is already taken.
| Use Case | rowspan Value | Notes |
|---|---|---|
| Single row cell | rowspan="1" | Default behavior |
| Merge two rows | rowspan="2" | Most common merge |
| Category label column | rowspan="N" | N = rows in group |
| JavaScript DOM | cell.rowSpan = 3 | Capital S in rowSpan |
| Applicable elements | td, th | Inside table only |
| Horizontal merge | colspan | Separate attribute |
| Element | Supported? | Notes |
|---|---|---|
<td> | Yes | Data cells |
<th> | Yes | Header cells; pair with scope |
<table> | No | Set rowspan on cells, not the table |
<textarea> | No | Use rows for textarea height |
<div> | No | Table-only attribute |
rowspan vs colspan vs rows| Attribute | Element | Direction | Purpose |
|---|---|---|---|
rowspan | td, th | Vertical (rows) | Merge table cells downward |
colspan | td, th | Horizontal (columns) | Merge table cells sideways |
rows | textarea | N/A (not a merge) | Visible textarea height in lines |
Basic vertical cell merge, dynamic rowSpan in JavaScript, and combining rowspan with colspan.
Cell in column 2 spans two rows with rowspan="2":
| Row 1, Cell 1 | Row 1–2, Cell 2 (rowspan=2) | Row 1, Cell 3 |
| Row 2, Cell 1 | Row 2, Cell 3 | |
| Row 3, Cell 1 | Row 3, Cell 2 | Row 3, Cell 3 |
rowspanMerge the second column across the first two rows:
<table border="1">
<tr>
<td>Row 1, Cell 1</td>
<td rowspan="2">Row 1–2, Cell 2 (rowspan=2)</td>
<td>Row 1, Cell 3</td>
</tr>
<tr>
<td>Row 2, Cell 1</td>
<td>Row 2, Cell 3</td>
</tr>
<tr>
<td>Row 3, Cell 1</td>
<td>Row 3, Cell 2</td>
<td>Row 3, Cell 3</td>
</tr>
</table>The cell with rowspan="2" covers rows 1 and 2 in column 2. Row 2 has only two <td> elements because column 2 is already occupied.
Set vertical span programmatically with the rowSpan property:
<td id="dynamicCell">Spans 3 rows</td>
<script>
document.getElementById("dynamicCell").rowSpan = 3;
</script>cell.rowSpan = 3 stretches the cell across three rows. Note the capital S in the DOM property rowSpan.
rowspan + colspanUse both attributes on one cell for a corner header block:
<table border="1">
<tr>
<th rowspan="2" colspan="2">Sales Report</th>
<th>Q1</th>
<th>Q2</th>
</tr>
<tr>
<th>Jan–Mar</th>
<th>Apr–Jun</th>
</tr>
<tr>
<td>North</td>
<td>East</td>
<td>$12k</td>
<td>$15k</td>
</tr>
</table>rowspan="2" colspan="2" makes one header cell cover a 2×2 block. Plan row and column counts carefully when combining both.
scope="rowgroup" or scope="row" where appropriate.<caption> to describe the table purpose.Pick how many rows one td or th should cover.
Following rows skip that column slot.
The cell grows vertically across row slots.
Related rows share one vertical label or value cell.
The rowspan attribute is supported in all modern browsers on <td> and <th> elements.
All major browsers render rowspan consistently on table cells.
Bottom line: Use rowspan confidently for table layouts; test complex merges across browsers.
colspan for corner header blocks when neededscope for accessibilityrowspan with textarea rowsThe rowspan attribute is a valuable tool for structured HTML tables, letting one cell cover multiple rows vertically.
Start with simple two-row merges, then build up to grouped category columns and combined rowspan + colspan headers. Always verify that each row’s effective column total stays correct.
rowspanBookmark these before merging your next table rows.
Span rows.
PurposeCell elements.
ScopeRow count.
ValuesCapital S in JS.
ScriptTextarea differs.
Gotcha<td> and <th> inside a <table>. Other elements ignore rowspan.rowspan merges table cells vertically. rows sets textarea visible height in lines.rowspan spans rows vertically. colspan spans columns horizontally.cellElement.rowSpan = 3 (capital S) or setAttribute("rowspan", "3").Practice the rowspan attribute with vertical merges and JavaScript examples in the Try It editor.
3 people found this page helpful