Grid

Add arrow-key navigation to a grid. Set the column count, then move by cell, row, row ends, grid ends or pages, with arrows that flip in right-to-left text.

Set data-keyrove-cols above 1 to navigate a grid. ↑/↓ move one row in the same column; ←/→ move one cell in DOM order.

Live · time slots
<div id="time-slots" data-keyrove-cols="6" data-keyrove-page-length="2">
  <button data-keyrove-item tabindex="0">09:00</button>
  <button data-keyrove-item tabindex="0">09:30</button>
  <button data-keyrove-item tabindex="0">10:00</button>
  <!-- … -->
  <button data-keyrove-item tabindex="0">17:30</button>
</div>

The demo sets data-keyrove-cols="6" and data-keyrove-page-length="2", so a page is two rows. The column count is the one keyrove navigates by, so keep it in step with the layout: a CSS grid-template-columns of six and a data-keyrove-cols of four will move focus in a way that does not match what is on screen.

Moves in a grid

MoveDefault keyAttributeAt the edge
Next cell→data-keyrove-next-keyFlows on to the next row's first cell; stops at the grid's last cell
Previous cell←data-keyrove-prev-keyFlows back to the previous row's last cell; stops at the first cell
Next row↓data-keyrove-next-row-keySame column; stops at the bottom
Previous row↑data-keyrove-prev-row-keySame column; stops at the top
Row start / endHome / Enddata-keyrove-home-row-key / data-keyrove-end-row-keyFirst / last navigable cell of the focused row
Grid start / endCtrl+Home / Ctrl+Enddata-keyrove-home-key / data-keyrove-end-keyFirst / last navigable cell of the grid
PagePageDown / PageUpdata-keyrove-page-down-key / data-keyrove-page-up-keypage-length rows, same column; an overshoot lands on the grid's last / first navigable cell
  • A cell move follows DOM order, like a caret in text, so the cell pair reaches every cell in the grid.
  • Grids never wrap; data-keyrove-loop is ignored.
  • A grid is entered from outside by any of its four arrows, landing on the first cell.
  • Rebind any move and the replaced default goes back to its browser behavior; see custom keys.

At an edge, the key is still consumed and the readout shows an amber no-op. Holding ↓ at the bottom of the grid therefore does not scroll the page.

Right-to-left grids

Under dir="rtl" the default cell arrows flip: ← is the next cell and → the previous, each still moving the way it points on screen. The row arrows and any explicit binding stay put. See horizontal groups and RTL for how the direction is resolved.

Responsive grids

The column count is read from the attribute on every keypress, not cached, so a grid whose layout changes only needs the attribute kept current. Responsive grid lets the stylesheet decide it.