Spanning Cells with colspan and rowspan

One cell covering several columns or rows. Simple to write, easy to get wrong, and the arithmetic has to balance or the whole grid tears.

Concept

colspan makes a cell stretch across several columns; rowspan makes it stretch down several rows. Both take a positive integer and both can be used on th or td.

<td colspan="3">This cell covers three columns</td>
<td rowspan="2">This cell covers two rows</td>
<td colspan="2" rowspan="2">A two by two block</td>

The arithmetic

Every row must account for the same number of columns, and a spanned cell counts once for each column it covers. This is where most broken tables come from.

<!-- a four column table -->
<table>
  <tr>
    <td colspan="2">A</td>   <!-- 2 -->
    <td>B</td>               <!-- 1 -->
    <td>C</td>               <!-- 1 -->  total 4, correct
  </tr>
  <tr>
    <td>D</td><td>E</td><td>F</td><td>G</td>   <!-- 4, correct -->
  </tr>
</table>

A rowspan takes a slot in the rows below it. Those rows must therefore be written with fewer cells, because the spanning cell has already filled one of their positions.

<table>
  <tr>
    <td rowspan="2">Monday</td>   <!-- occupies row 1 and row 2, column 1 -->
    <td>09:00</td>
    <td>Design studio</td>
  </tr>
  <tr>
    <!-- no cell for column 1: Monday is still there -->
    <td>11:00</td>
    <td>Typography</td>
  </tr>
</table>

Add a cell to that second row and everything after it shifts right, leaving a table one column wider than the header. The browser will not warn you; it will simply draw the wrong grid.

Example: a timetable

<table>
  <caption>Studio timetable, semester one</caption>
  <thead>
    <tr>
      <th scope="col">Day</th>
      <th scope="col">Time</th>
      <th scope="col">Session</th>
      <th scope="col">Room</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="rowgroup" rowspan="2">Monday</th>
      <td>09:00</td><td>Design studio</td><td>B12</td>
    </tr>
    <tr>
      <td>11:00</td><td>Typography</td><td>B14</td>
    </tr>
    <tr>
      <th scope="row">Tuesday</th>
      <td>10:00</td><td>Workshop</td><td>Ground floor</td>
    </tr>
    <tr>
      <td colspan="4">Wednesday: no scheduled sessions</td>
    </tr>
  </tbody>
</table>

Explanation

Monday spans two rows, so the second Monday row omits its first cell. Its scope is rowgroup rather than row, because it labels both rows rather than one. The Wednesday note spans all four columns, which is the standard way to write a full width message inside a table.

Grouped column headers

A two row header is the most common use of colspan:

<thead>
  <tr>
    <th rowspan="2" scope="col">Course</th>
    <th colspan="2" scope="colgroup">Semester 1</th>
    <th colspan="2" scope="colgroup">Semester 2</th>
  </tr>
  <tr>
    <th scope="col">Theory</th>
    <th scope="col">Practical</th>
    <th scope="col">Theory</th>
    <th scope="col">Practical</th>
  </tr>
</thead>

Read the arithmetic: row one is 1 + 2 + 2 = 5; row two is 4 cells plus the one still occupied by the rowspan above = 5. Balanced.

Accessibility warning

Spanned cells make a table harder for assistive technology to interpret, and the more complex the spanning, the less reliable the automatic header association becomes. Two consequences:

  • Use scope="colgroup" and scope="rowgroup" on spanning headers so their reach is explicit.
  • When the structure is genuinely complex, drop scope and use explicit id and headers attributes instead. That is covered in the next note.

The better answer is usually to simplify. Two straightforward tables almost always beat one clever one.

Important rules

  • Values must be positive integers. colspan="0" is invalid and rowspan="0" - meaning to the end of the row group - is unreliable.
  • Every row must total the same column count once spans are included.
  • A rowspan consumes a position in each row it reaches into.
  • Spans must not overlap. Overlapping spans produce undefined layout.
  • colspan is capped at 1000 by the specification.

Common mistakes

  • Writing a full set of cells in a row that a rowspan already reaches into.
  • Miscounting a colspan and shifting everything after it.
  • Using spans to build a layout rather than to express real structure.
  • Leaving scope="col" on a header that spans several columns.
  • Nesting a table inside a spanned cell to avoid doing the arithmetic.
  • Assuming the browser will flag the error. It will not.

Best practices

  • Sketch the grid on paper before writing a spanned table.
  • Comment the column count at the top of a complex table.
  • Prefer two simple tables over one heavily spanned one.
  • Use colgroup and rowgroup scopes on spanning headers.
  • Validate. The validator catches mismatched column counts immediately.
  • Test with a screen reader whenever a table has more than one header row.

Practice

  1. Build a five column table with a two row header where the first column spans both header rows. Check the arithmetic on both rows.
  2. Write a timetable where a day label spans three rows, then validate it.
  3. Deliberately add one extra cell to a row under a rowspan. Describe what happens and how the validator reports it.
  4. Take a complex spanned table and split it into two simple ones. Which is easier to read aloud?

Useful resources

Hand picked references for this topic
Written by Lorens Mishra

Default administrator account created by the installer.

Continue reading

All HTML notes →

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.