Skip to content
easeweb
Search topics

Editable data grids a keyboard can't move through or edit

The cells of a table of values take only a click, which turns them into fields, with or without role="grid", so the keyboard can't reach a cell and the field a click opens has no name.

WCAG 2.2
SC 2.1.1ASC 4.1.2A
Required by
Section 508 · EN 301 549 (EU)
Broken cell.onclick = () => edit(cell);
The accessibility problem illustrated: Motor:How do I change a price?
01

The problem

Keyboard users can't reach a cell of the table to change it, and screen reader users aren't told that a value can be changed, or what the field that opens is for.

02

Try it

Change the price of Paper cups to 0.15 using only the keyboard.

  1. Broken 1: press Tab. Focus goes past the table to Save changes, so no price can be reached. Click a price: the field that opens is read with no item or column.
  2. Broken 2: the same table, with role="grid" added. Tab still passes every cell, there is nowhere to press an arrow key, and the field a click opens is still read with no item or column.
  3. Apply the fix. In the grid, Tab once, move with the arrow keys, press Enter or F2 to edit, Enter to keep the change and Escape to cancel.

Broken Can you fix this?

Stock

ItemPriceIn stock
Oat milk2.4036
Paper cups0.12500
Espresso beans14.008

Screen reader says:

(Tab into the sheet, or click a price)

A recreated demo. The broken version is intentionally inaccessible.

03

The fix

Make every editable cell one the keyboard can reach and open, and name the field that edits it by its row and column.

  1. 1Every editable cell can be reached and edited from the keyboard.
  2. 2Every field that edits a cell is named by its row and its column.
  3. 3A role="grid" gets everything it promises, one Tab stop, the arrow keys and a key into each cell; without them, put a field in each cell.
Before

A table whose cells open only on click

<h2 id="stock-title">Stock</h2><table class="sheet"  aria-labelledby="stock-title">  <thead>    <tr>      <th scope="col">Item</th>      <th scope="col">Price</th>      <th scope="col">In stock</th>    </tr>  </thead>  <tbody>    <tr>      <th scope="row">Oat milk</th>      <td>2.40</td>      <td>36</td>    </tr>    <tr>      <th scope="row">Paper cups</th>      <td>0.12</td>      <td>500</td>    </tr>    <tr>      <th scope="row">Espresso beans</th>      <td>14.00</td>      <td>8</td>    </tr>  </tbody></table><button type="button">Save changes</button>
After

A field in each cell

<h2 id="stock-title">Stock</h2><table class="sheet"  aria-labelledby="stock-title">  <thead>    <tr>      <th scope="col" id="col-item">Item</th>      <th scope="col" id="col-price">Price</th>      <th scope="col" id="col-stock">In stock</th>    </tr>  </thead>  <tbody>    <tr>      <th scope="row" id="row-oat">Oat milk</th>      <td>        <input value="2.40"          aria-labelledby="row-oat col-price">      </td>      <td>        <input value="36"          aria-labelledby="row-oat col-stock">      </td>    </tr>    <tr>      <th scope="row" id="row-cups">Paper cups</th>      <td>        <input value="0.12"          aria-labelledby="row-cups col-price">      </td>      <td>        <input value="500"          aria-labelledby="row-cups col-stock">      </td>    </tr>    <tr>      <th scope="row" id="row-beans">Espresso beans</th>      <td>        <input value="14.00"          aria-labelledby="row-beans col-price">      </td>      <td>        <input value="8"          aria-labelledby="row-beans col-stock">      </td>    </tr>  </tbody></table><button type="button">Save changes</button>

Why this fix: Use native HTML first

Fixing this with an AI coding assistant? Get this guide as Markdown, or get every guide in your coding agent.

04

Verify the fix

4 checks, no mouse.

Test with: Keyboard, Screen reader, Forced colors, Zoom

0 of 4 checked

Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the sheet, its component or its library changes.

Limits

This is a starting pattern, not a guarantee for every application. The grid script is a minimal sketch: it has no typing to start editing, no Page Up or Page Down, no selection, no copy and paste, and no loading of rows on demand. Sorting by a column is a separate failure, covered by the topic on sortable tables saying which column is sorted, and which way. The same one-Tab-stop pattern, for a sidebar, is shown in tree views keyboards can't open and screen readers flatten. Data grid components in libraries vary: check that the one you use reaches every cell and handles every key before relying on it. Test the complete journey with your target assistive technology.

This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.

Keep this fixed as your code changes.

Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.

How retests work