nuxt / nuxt/ui

Table: rows with @select become keyboard-inert buttons (role="row" lost, no key handler, nested-interactive)

Open
#6,837 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
6.9k
Forks
1.1k
Avg merge
1d 7h
Merged PRs (30d)
57

Description

Package

v4.x (present on v4 head — Table.vue lines 552–553)

Description

When @select is bound, each <tr> is rendered with:

:role="props.onSelect ? 'button' : undefined"
:tabindex="props.onSelect ? 0 : undefined"

and no keydown/keyup handler is bound anywhere in the component (0 occurrences in the file) — only @click. Three consequences, all measured with axe + manual keyboard testing on a populated table:

  1. Keyboard-inert focus stops (WCAG 2.1.1). Every row is focusable and announces as a button, but pressing Enter/Space does nothing — verified by focusing a row and pressing Enter: no navigation. Keyboard users can tab into hundreds of rows that lead nowhere (see also #6710 for the tab-order half of this).
  2. role="row" is lost. With the role overridden to button, [role="row"] matches nothing on a populated grid; the table's semantics are gone for AT (and for test selectors).
  3. nested-interactive (axe, serious, once per row). With selectable + row selection checkboxes, each "Select row" checkbox is now a control inside a button.
Suggested fix

Either bind a real key handler and keep an ARIA-correct pattern, or drop both attributes: @click still fires for pointer users, and keyboard access to the record is conventionally provided by a real link in the primary cell (the standard data-grid pattern, with native focus, native Enter, and open-in-new-tab). We have been running with both attributes removed, plus a link in the primary cell, across ~194 entity list pages gated by axe in CI: 0 violations, keyboard access works.

Reproduction

Docs example as-is: https://ui.nuxt.com/docs/components/table#with-row-select-event — bind @select, focus a row, press Enter (nothing happens); run axe with a selection column (nested-interactive per row); query [role="row"] (no matches on body rows).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with src/runtime/components/Table.vue at lines 552–553 and reproduce the documented row-select behavior using the Table docs example. Check keyboard activation, [role="row"] queries, and axe results with a selection column; done means the chosen pattern preserves keyboard access and removes the reported accessibility violations.

Written by the indexing model from the issue text.

Assessment

Tech stack
nuxt, typescript
Domain
accessibility, frontend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.