Loading Developer Playground

Loading ...

Skip to main content
ARIA ROLEโ€ขComposite RolesData intensiveRoving tabindexMulti-select support

grid

An interactive data surface that arranges information in rows and columns. People can navigate, edit, or select cells similar to a spreadsheet or data table.

Live Example

Editable Data Grid

Spreadsheet-like grid with cell-level focus management and arrow key navigation.

Arrow keys move cell focus โ€ข Home/End jump across rowCell 1/3, Column 1/3
Team
Lead
Status
Platform
Ravi Patel
Green
Design Systems
June Park
Amber
Payments
Luis Alvarez
Blocked

Purpose

Present tabular data with keyboard navigation, sorting, and optional inline editing.

Structure

Contains row elements composed of gridcell, columnheader, or rowheader roles.

Screen Reader

Announces row/column coordinates and supports table-style reading commands.

When to Use

1

Data tables with inline actions

Financial dashboards, issue trackers, or CMS listing screens that require quick editing.

2

Spreadsheet-like interfaces

Provide arrow-key navigation and editing in place without leaving the context of the table.

3

Calendars and schedulers

Represent days, times, or seats in grid formations with consistent keyboard controls.

Required Structure

Rows and Gridcells

Each direct child of the grid must be role="row". Each row must contain role="gridcell" (or header) children.

Focusable Model

Only one cell should be in the tab order at a time. Implement roving tabindex or aria-activedescendant.

Headers

Include columnheader / rowheader cells and connect them via aria-describedby or aria-labelledby for clarity.

Keyboard Interaction Model

ActionKeysResult
Move within rowArrowLeft / ArrowRightFocuses the adjacent gridcell in the same row.
Move between rowsArrowUp / ArrowDownFocuses the gridcell above or below while staying in the same column.
Jump to edgesHome / EndMoves to the first or last cell in the current row.
Jump to top/bottomCtrl + Home / Ctrl + EndMoves to the first cell of the grid or the last cell respectively.
Page navigationPageUp / PageDownScrolls the view by a page and updates focus to the same column in the newly visible row.
Selection toggleSpace / Shift + ArrowMarks the current cell (or range) as selected when aria-multiselectable is true.

Required States & Properties

aria-rowcountOptional

Total number of rows. Use when virtualizing so assistive tech knows the dataset size.

aria-colcountOptional

Total number of columns, especially when columns can be hidden or virtualized.

aria-rowindexOptional

Applied to rows to represent their 1-based index inside the full data set.

aria-colindexOptional

Applied to gridcells to communicate the column index.

aria-multiselectableOptional

Set to true when multiple cells, rows, or columns can be selected simultaneously.

aria-activedescendantOptional

Alternative to roving tabindex; reference the focused cell id while keeping DOM focus on the grid.

aria-readonlyOptional

Mark the entire grid or specific cells as read-only to manage editing expectations.

Implementation Checklist

  • โœ“

    Preserve DOM order that matches the visual grid so screen readers can follow relationships.

  • โœ“

    Provide clear cell boundaries and focus outlines so sighted keyboard users can track position.

  • โœ“

    Announce sorting state with aria-sort on columnheader elements whenever the user sorts a column.

  • โœ“

    If editing is supported, describe the mode switch (e.g., Enter to edit, Escape to cancel).

  • โœ“

    For large datasets, virtualize rows but keep aria-rowcount/aria-rowindex accurate to avoid confusion.

Code Examples

Static Grid Structure

Shows explicit row and gridcell roles with headers bound via aria-describedby.

<div role="grid" aria-rowcount="3" aria-colcount="3">
  <div role="row">
    <div role="columnheader" id="col-name">Name</div>
    <div role="columnheader" id="col-role">Role</div>
    <div role="columnheader" id="col-status">Status</div>
  </div>
  <div role="row">
    <div role="rowheader" id="row-1">Order #2458</div>
    <div role="gridcell" aria-describedby="col-role row-1">Fulfillment</div>
    <div role="gridcell" aria-describedby="col-status row-1">In progress</div>
  </div>
</div>

Roving Tabindex Grid

JavaScript roves tabindex so only one cell is in the tab order.

const grid = document.querySelector('[role="grid"]')
const cells = Array.from(grid.querySelectorAll('[role="gridcell"]'))

function setActiveCell(nextIndex) {
  cells.forEach((cell, index) => {
    cell.tabIndex = index === nextIndex ? 0 : -1
  })
  cells[nextIndex].focus()
}

let activeIndex = 0
setActiveCell(activeIndex)

grid.addEventListener('keydown', (event) => {
  const colCount = 3
  if (event.key === 'ArrowRight') {
    event.preventDefault()
    activeIndex = Math.min(activeIndex + 1, cells.length - 1)
  } else if (event.key === 'ArrowLeft') {
    event.preventDefault()
    activeIndex = Math.max(activeIndex - 1, 0)
  } else if (event.key === 'ArrowDown') {
    event.preventDefault()
    activeIndex = Math.min(activeIndex + colCount, cells.length - 1)
  } else if (event.key === 'ArrowUp') {
    event.preventDefault()
    activeIndex = Math.max(activeIndex - colCount, 0)
  } else {
    return
  }
  setActiveCell(activeIndex)
})

Best Practices

๐ŸชŸ

Keep headers sticky

Repeatedly announce column headers with aria-describedby so users never lose context.

๐Ÿงญ

Expose coordinates

Visually show row/column indices to mirror what assistive tech announces.

๐Ÿงน

Manage focus on refresh

When data updates, keep the active cell in place to avoid focus loss.

Common Mistakes

Skipping row or cell roles

A div with role="grid" contains plain div children. Screen readers cannot understand the structure.

Apply role="row" to each row container and role="gridcell"/header to each cell.

Multiple tabbable cells

Every gridcell has tabindex="0", forcing users to tab hundreds of times.

Implement roving tabindex or aria-activedescendant so only one cell is tabbable.

Related Roles & Patterns

row

Child container that groups gridcells horizontally.

Learn more

gridcell

Interactive cell that contains data or controls.

Learn more

treegrid

Hybrid between grid and tree to express hierarchy.

Learn more