aria-colindex
Defines an element's column index or position with respect to the total number of columns within a table, grid, or treegrid.
Overview
The aria-colindex attribute defines an element's column index or position within a table, grid, or treegrid. The value is an integer greater than or equal to 1, representing the column position.
This attribute is essential when implementing virtual scrolling or displaying a subset of columns. It tells assistive technologies the true position of each visible cell within the complete grid structure.
When used on a row element, aria-colindex defines the column index of the first cell in that row, and child cells inherit sequential indices.
Live Demo: Virtual Column Scrolling
| Acolindex: 1 | Bcolindex: 2 | Ccolindex: 3 | Dcolindex: 4 |
|---|---|---|---|
| A1 | B1 | C1 | D1 |
| A2 | B2 | C2 | D2 |
| A3 | B3 | C3 | D3 |
Each cell has aria-colindex indicating its true column position. Screen readers announce "Column 1 of 10" for the first visible cell, helping users understand their position in the full grid.
Code Examples
Basic Usage
<!-- aria-colindex indicates a cell's column position -->
<!-- Sparse table showing columns 1, 2, 5, and 8 of 10 -->
<table role="grid" aria-colcount="10" aria-label="Sales data">
<thead>
<tr>
<th aria-colindex="1">ID</th>
<th aria-colindex="2">Product</th>
<th aria-colindex="5">Price</th>
<th aria-colindex="8">Stock</th>
</tr>
</thead>
<tbody>
<tr>
<td aria-colindex="1">001</td>
<td aria-colindex="2">Widget</td>
<td aria-colindex="5">$29.99</td>
<td aria-colindex="8">150</td>
</tr>
</tbody>
</table>
<!-- Screen reader: "Column 5 of 10, Price" -->Grid with Navigation
<!-- Grid with keyboard navigation using aria-colindex -->
<div
role="grid"
aria-colcount="100"
aria-label="Spreadsheet"
tabindex="0"
>
<div role="row" aria-rowindex="1">
<!-- Only columns 25-30 visible in viewport -->
<div role="columnheader" aria-colindex="25">Y</div>
<div role="columnheader" aria-colindex="26">Z</div>
<div role="columnheader" aria-colindex="27">AA</div>
<div role="columnheader" aria-colindex="28">AB</div>
<div role="columnheader" aria-colindex="29">AC</div>
<div role="columnheader" aria-colindex="30">AD</div>
</div>
<div role="row" aria-rowindex="2">
<div role="gridcell" aria-colindex="25" tabindex="-1">Y2</div>
<div role="gridcell" aria-colindex="26" tabindex="-1">Z2</div>
<div role="gridcell" aria-colindex="27" tabindex="-1">AA2</div>
<div role="gridcell" aria-colindex="28" tabindex="-1">AB2</div>
<div role="gridcell" aria-colindex="29" tabindex="-1">AC2</div>
<div role="gridcell" aria-colindex="30" tabindex="-1">AD2</div>
</div>
</div>With Column Spanning
<!-- aria-colindex with spanning cells -->
<table role="grid" aria-colcount="6">
<thead>
<tr>
<!-- Header spans columns 1-2 -->
<th aria-colindex="1" aria-colspan="2">Name</th>
<!-- Header at column 3 -->
<th aria-colindex="3">Age</th>
<!-- Header spans columns 4-6 -->
<th aria-colindex="4" aria-colspan="3">Contact Info</th>
</tr>
</thead>
<tbody>
<tr>
<td aria-colindex="1">First</td>
<td aria-colindex="2">Last</td>
<td aria-colindex="3">32</td>
<td aria-colindex="4">Email</td>
<td aria-colindex="5">Phone</td>
<td aria-colindex="6">Address</td>
</tr>
</tbody>
</table>React Component
// React component with aria-colindex for virtual columns
import { useState, useCallback } from 'react';
interface VirtualGridProps {
totalColumns: number;
totalRows: number;
visibleColumnCount: number;
getCellValue: (row: number, col: number) => string;
}
function VirtualGrid({
totalColumns,
totalRows,
visibleColumnCount,
getCellValue
}: VirtualGridProps) {
const [startCol, setStartCol] = useState(1);
const [focusedCell, setFocusedCell] = useState({ row: 1, col: 1 });
const visibleColumns = Array.from(
{ length: visibleColumnCount },
(_, i) => startCol + i
).filter(col => col <= totalColumns);
const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
const { row, col } = focusedCell;
switch (e.key) {
case 'ArrowRight':
if (col < totalColumns) {
const newCol = col + 1;
setFocusedCell({ row, col: newCol });
// Scroll viewport if needed
if (newCol >= startCol + visibleColumnCount) {
setStartCol(newCol - visibleColumnCount + 1);
}
}
e.preventDefault();
break;
case 'ArrowLeft':
if (col > 1) {
const newCol = col - 1;
setFocusedCell({ row, col: newCol });
if (newCol < startCol) {
setStartCol(newCol);
}
}
e.preventDefault();
break;
// ... handle up/down for rows
}
}, [focusedCell, startCol, totalColumns, visibleColumnCount]);
return (
<div
role="grid"
aria-colcount={totalColumns}
aria-rowcount={totalRows}
aria-label="Data grid"
onKeyDown={handleKeyDown}
>
<div role="row" aria-rowindex={1}>
{visibleColumns.map(col => (
<div
key={col}
role="columnheader"
aria-colindex={col}
>
Column {col}
</div>
))}
</div>
{Array.from({ length: 5 }, (_, rowIdx) => (
<div key={rowIdx + 2} role="row" aria-rowindex={rowIdx + 2}>
{visibleColumns.map(col => (
<div
key={col}
role="gridcell"
aria-colindex={col}
tabIndex={
focusedCell.row === rowIdx + 2 && focusedCell.col === col
? 0 : -1
}
>
{getCellValue(rowIdx + 2, col)}
</div>
))}
</div>
))}
</div>
);
}
