The HTML aria-colspan attribute
The aria-colspan attribute gives assistive technology a cell's column span in a table built from ARIA roles. On <td> and <th>, use the HTML colspan attribute instead. The value is a whole number of at least 1, and the visual span is yours to create in CSS.
Overview
The aria-colspan attribute defines how many columns a cell or gridcell covers. It's intended for cells outside a native table, such as a div with role="cell", and the default is 1.
The value must be an integer of at least 1, and less than the value that would make the cell overlap the next cell in its row. A four-column row with one two-column cell therefore holds three cells.
On a real <td> or <th>, use colspan, and browsers must ignore aria-colspan where colspan is available. Avoid putting both on one element, and never give them different values, which doesn't conform.
A native cell is placed by colspan. With colspan="2" and aria-colspan="3" on one td, the cell's table span is 2, though Chrome's and Firefox's trees still list 3 among its accessibility attributes.
After a native colspan="2", the next cell reports column 3. After aria-colspan="2", Chrome and Firefox report column 2 until you give it aria-colindex="3". Under WAI-ARIA, a browser can derive that position, but in those two, cells after an ARIA span need aria-colindex.
Syntax
<div role="table" aria-label="Team calendar">
<div role="row">
<span role="cell" aria-colindex="1" aria-colspan="2">Trip</span>
<span role="cell" aria-colindex="3">Office</span>
</div>
</div>
Values
| Value |
|---|
| An integer greater than or equal to 1. |
Example
<p>Pick a length. The script sets aria-colspan and the CSS span together.</p>
<label for="days">Trip length</label>
<select id="days">
<option value="1">1 day</option>
<option value="2" selected>2 days</option>
<option value="3">3 days</option>
<option value="4">4 days</option>
</select>
<div role="table" aria-label="Team calendar" style="margin: 10px 0">
<div role="row" style="display: grid; grid-template-columns: 3rem repeat(4, 1fr); gap: 2px; font-weight: bold">
<span role="columnheader">Name</span>
<span role="columnheader">Mon</span>
<span role="columnheader">Tue</span>
<span role="columnheader">Wed</span>
<span role="columnheader">Thu</span>
</div>
<div role="row" style="display: grid; grid-template-columns: 3rem repeat(4, 1fr); gap: 2px">
<span role="rowheader">Ana</span>
<span role="cell" id="trip" aria-colindex="2" aria-colspan="2" style="grid-column: span 2; background: #dbeafe; color: #1e3a5f">Trip</span>
<span role="cell" class="day" aria-colindex="3" hidden>Office</span>
<span role="cell" class="day" aria-colindex="4">Office</span>
<span role="cell" class="day" aria-colindex="5">Office</span>
</div>
<div role="row" style="display: grid; grid-template-columns: 3rem repeat(4, 1fr); gap: 2px">
<span role="rowheader">Ben</span>
<span role="cell" aria-colindex="2">Office</span>
<span role="cell" aria-colindex="3">Office</span>
<span role="cell" aria-colindex="4">Office</span>
<span role="cell" aria-colindex="5">Office</span>
</div>
</div>
<p role="status" id="state"></p>
<script>
const days = document.getElementById('days');
const trip = document.getElementById('trip');
const state = document.getElementById('state');
const cells = [...document.querySelectorAll('.day')];
function update() {
const span = Number(days.value);
trip.setAttribute('aria-colspan', span);
trip.style.gridColumn = 'span ' + span;
cells.forEach(cell => {
cell.hidden = Number(cell.getAttribute('aria-colindex')) < 2 + span;
});
const next = cells.find(cell => !cell.hidden);
state.textContent = next
? 'aria-colspan is ' + span + ', and the next cell keeps aria-colindex ' + next.getAttribute('aria-colindex') + '.'
: 'aria-colspan is ' + span + ', so no cell follows in this row.';
}
document.querySelectorAll('[role="columnheader"]').forEach((cell, i) => cell.setAttribute('aria-colindex', i + 1));
document.querySelectorAll('[role="rowheader"]').forEach(cell => cell.setAttribute('aria-colindex', 1));
days.addEventListener('change', update);
update();
</script>
Best practices
- Rule out a native table before you add aria-colspan. A <table> makes the markup less verbose and accessible by default.
- Write the CSS span and the ARIA value from one number, in one function, as with
grid-column: span 2besidearia-colspan="2". - Take the cells a span covers out of the row, by removing them or setting hidden. Left in place, they'd break the rule against overlapping the next cell.
- When a span grows or shrinks, check that each later cell's aria-colindex still matches the column it sits in.























