Command Palette

Search for a command to run...

Hectal
PHASE 3Beginner ~20 min· topic 3 of 4

Topic 3.3

Spanning Rows and Columns

In one line

colspan stretches a cell across several columns and rowspan stretches it down several rows; each spanning cell takes over grid slots, so you must remove the cells it replaces.

Think of it like this

A school timetable. Most boxes hold one lesson in one period. But "Lunch break" covers the whole row, all days at once, and a double "Science lab" fills two periods in a row on Tuesday. On paper you rub out the lines between those boxes and make one big box. In HTML, colspan and rowspan do exactly that.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

colspan
An attribute that makes a cell as wide as several columns, like colspan="3".
rowspan
An attribute that makes a cell as tall as several rows, like rowspan="2".
Slot
One place in the table's grid, where one row meets one column.
Grid
The pattern of rows and columns the browser builds from your cells.
Spanning cell
A cell that covers more than one slot.
cellIndex
A cell's position among the cells written in its row (counting from 0), not its column on screen.

Step by step

01Sketch the grid first

Write the table as a grid of text. Mark which boxes join: here Lab covers Tuesday 9:00 and 10:00, and Lunch covers all three days at 11:00.

plan.txtwhole filetext
        | Mon   | Tue   | Wed
 9:00   | Maths | Lab   | English
10:00   | Hindi | (Lab) | Maths
11:00   | Lunch  ————————————————
12:00   | Art   | Music | Sports

02Write the rows that have no spans

The header row and the 12:00 row are plain: four cells each, one per column.

timetable.htmlwhole filehtml
<tr><th>Time</th><th>Mon</th><th>Tue</th><th>Wed</th></tr>
...
<tr><th>12:00</th><td>Art</td><td>Music</td><td>Sports</td></tr>

03Add the rowspan, then remove the cell it covers

The Lab cell starts in the 9:00 row with rowspan="2". In the 10:00 row, Tuesday's slot is already taken, so that row lists only three cells: the time, Monday and Wednesday.

timetable.htmlwhole filehtml
<tr><th>9:00</th><td>Maths</td><td rowspan="2">Lab</td><td>English</td></tr>
<tr><th>10:00</th><td>Hindi</td><td>Maths</td></tr>

04Add the colspan

Lunch covers three day-columns, so the 11:00 row has the time cell plus one cell with colspan="3": 1 + 3 = 4 slots, the right count.

timetable.htmlwhole filehtml
<tr><th>11:00</th><td colspan="3">Lunch break</td></tr>

05Check every row adds up

Count the slots per row: 9:00 has 4 cells; 10:00 has 3 cells plus 1 slot from Lab above = 4; 11:00 has 1 + 3 = 4; 12:00 has 4. Every row fills 4 columns, so the grid is clean.

Check every row adds updiagram
Rendering diagram…

Try it yourself

  1. 1

    Make lunch shorter

    In the timetable, change Lunch to colspan="2". Predict what happens to Wednesday at 11:00 before you run. Then add a <td>Free</td> to fill the gap.

  2. 2

    Fix the ghost column

    In the second example, delete the second <td>Asha</td>. Predict the new cell count for row 3, then run and check the 4th column has gone.

  3. 3

    Add a third round

    In the grid example, make Round span 3 columns, add a <th>3</th> and a score for each player. Predict the printed grid first; every line should have 4 entries.

Code & diagrams

A timetable with both kinds of span New tab

Wednesday's Maths is in the 4th column on screen, but its `cellIndex` is 2: it counts written cells, not columns.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Lab rowSpan: 2
Lunch colSpan: 3
Cells written in the 10:00 row: 3
cellIndex of Wednesday's Maths: 2
One cell too many: a ghost column appears New tab

Every row has 3 cells, which looks right, but row 3 forgot that `Asha` above already fills its first slot. Its cells shift right and `9` sticks out into a 4th column. Delete the second `<td>Asha</td>` to fix it.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Row 1 has 3 cells written
Row 2 has 3 cells written
Row 3 has 3 cells written
Map the real grid with JavaScript New tab

This is the browser's placement rule in a few lines of code: find the first free slot, then mark every slot the cell covers. A two-level header: `Round` spans two columns and `Player` spans two rows.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Player | Round | Round
Player | 1 | 2
Asha | 8 | 9
Ravi | 7 | 10

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Add a rowspan but keep the covered cell

In the timetable, add <td>PE</td> back into the 10:00 row between Hindi and Maths.

terminal
$ the page shows
── what you'll see ──
PE appears under Wednesday, and Maths sticks out into a new 5th column that no other row fills.

Break #2

Span further than the section

Give Science lab rowspan="9" in a table with only four body rows.

terminal
$ the page shows
── what you'll see ──
The cell stops at the last row of its tbody. It does not cover the tfoot or create new rows, and nothing warns you.

Myth vs fact

Myth

colspan merges the contents of the cells next to it.

Fact

It only makes one cell wider. The cells it replaces must be removed from the HTML; any content in them has to go somewhere else.

Myth

cellIndex tells you which column a cell is in.

Fact

It is the cell's position among the cells written in its row. When a rowspan from above takes a slot, the two numbers differ (Wednesday's Maths had cellIndex 2 but sat in column 4).

Myth

A big table with many spans is more readable.

Fact

Each span makes the grid harder to follow, especially for screen reader users. Use spans when the data really groups that way; otherwise repeat the value or split the table.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    The HTML Living Standard defines the exact table processing model: slots are assigned with a "current column" that skips cells taken from above, which is the algorithm in the third live example. Overlapping cells are a "table model error"; browsers still render something, but results vary, so validate complex tables (validator.w3.org flags these).

  • ▸

    colspan="0" is not "to the end": it is treated as 1. Only rowspan="0" has the "to the end of the row group" meaning.

  • ▸

    Screen readers read spanning headers for every slot they cover, so a th colspan="2" over two sub-headers announces both levels ("Round, 1, 8"). Deep nesting (three or more header levels) gets confusing fast; consider splitting into several simpler tables.

  • ▸

    Spans make JavaScript table work harder: sorting, filtering or highlighting a column must use a grid map like the one above, because row.cells[i] is not column i. Data-grid libraries often forbid row spans in the body for this reason.

Remember this

  1. 1

    Think of the table as a grid of slots: one slot where each row meets each column. Normally one cell fills one slot. colspan="3" (column span) makes a cell fill 3 slots across, in its own row. rowspan="2" (row span) makes a cell fill 2 slots down: its own row and the row below. A cell can have both, and then it covers a rectangle.

  2. 2

    The golden rule: every slot is filled exactly once. When a cell spans 3 columns, its row needs 2 fewer cells. When a cell spans 2 rows, the next row needs one fewer cell, and you leave that cell out of the HTML completely. Forget to remove a cell and it gets pushed out to a new column on the right; remove too many and the row ends early with an empty gap.

  3. 3

    How the browser places cells: it walks each row from left to right and puts each cell in the first free slot, skipping slots already taken by a rowspan from above. That's why, in the row under a two-row cell, you write the cells as if the taken slot weren't there.

  4. 4

    Plan before you type. Draw the table on paper (or in a text file) as a grid, mark the big boxes, then write each row by listing only the cells that start in that row. Count: for every row, the sum of the colspan values of its cells, plus the slots taken by rowspans from above, must equal the number of columns.

  5. 5

    Spans only stretch cells; they don't create or merge content. A spanning th labels every slot it covers: a header with colspan="2" over "Morning" labels both columns under it. That's how two-level headers work ("Round" over "1" and "2"), and Topic 3.4 shows how to make those headers clear to screen readers.

  6. 6

    Limits from the HTML standard: colspan must be 1 to 1000 and rowspan 0 to 65534 (larger values are clamped). rowspan="0" means "to the end of this row group". A span never crosses from one row group into another, so a rowspan in tbody stops at the end of that tbody.

Explain it without notes

01

Explain what colspan and rowspan do, and what you must remove from the HTML when you use each.

02

How does the browser decide which column a cell lands in?

03

Why can cell.cellIndex differ from the column a cell appears in?

04

When should you avoid spans even if they would make the table look neater?

Practice

01

Build a 3-column table (Day, Morning, Evening) for two days where Saturday's single activity Trip covers both Morning and Evening.

02

Build a table where one teacher's name, Mrs Rao, covers two rows of subjects: Maths and Physics.

Trade-offs

  • ↔

    Spans make grouped data look clean and avoid repeating values, but they complicate sorting, filtering and screen reader navigation.

  • ↔

    Repeating a value in every row is easier to process and read cell by cell, but looks busier on screen.

Done when you can

  • I can make a cell span several columns or rows.

  • I can work out which cells to remove when I add a span.

  • I can plan a table as a grid and check each row adds up to the column count.

  • I can build a two-level header with colspan and rowspan.

  • I know why cellIndex is not the same as the visual column.