Skip to content

feat(dockview-core): a11y polish — tab keyboard navigation + floating dialog name#1316

Merged
mathuo merged 2 commits into
masterfrom
feat/a11y-keyboard-tabs
Jun 10, 2026
Merged

feat(dockview-core): a11y polish — tab keyboard navigation + floating dialog name#1316
mathuo merged 2 commits into
masterfrom
feat/a11y-keyboard-tabs

Conversation

@mathuo

@mathuo mathuo commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Description

Two small accessibility improvements that complete the WAI-ARIA baseline shipped in #1314.

1. Tab strip keyboard navigation (WAI-ARIA Tabs pattern)

Makes the tab strip operable by keyboard:

  • Roving tabindex — only the active tab is in the tab order; the others are reachable via arrow keys.
  • Arrow keys move focus along the strip (Left/Right horizontal, Up/Down vertical per aria-orientation), clamped at the ends.
  • Home / End jump to the first / last tab.
  • Enter / Space activate the focused tab (manual activation — arrowing moves focus only, so it doesn't switch panels until committed).

The keydown handler lives on the tablist and only acts when a tab element itself is focused, so it never hijacks keys typed inside a custom tab renderer's controls. Focus movement between groups (F6/spatial) and keyboard docking are intentionally out of scope.

2. Floating-group dialog accessible name

The floating-group dialog (role="dialog", from #1314) now gets an accessible name from its representative group's active panel title, refreshed when the active panel changes. An untitled panel leaves the dialog unnamed rather than hard-coding a label string — no i18n surface introduced.

Type of change

  • New feature (keyboard navigation, dialog name)
  • Refactor / cleanup (roving tabindex)

Affected packages

  • dockview-core

How to test

accessibility.spec.ts adds a "tab keyboard navigation" suite (roving tabindex, arrow nav, end-clamping, Home/End, manual activation, Enter/Space) and a floating-dialog accessible-name test.

Checklist

  • yarn test passes (full dockview-core suite: 1051)
  • prettier-clean + eslint-clean on changed files; typecheck clean
  • npm run gen — no diff (no new public exports)
  • I have added tests
  • No breaking changes (additive; roving tabindex only changes inactive tabs from tabindex 0 → -1)

Note on the one behaviour change

Roving tabindex means inactive tabs are no longer individually Tab-reachable (they move from tabindex="0" to "-1"); you Tab to the strip once and arrow within it. This is the standard ARIA Tabs behaviour and the correct pairing for the roles shipped in #1314, but it is a (minor, conformant) change to keyboard tab-order.

Deliberately not included

Other "polish" ideas were left out because each introduces either a hardcoded i18n string or new public API, which deserve a deliberate decision rather than slipping in: a tablist accessible name ("Tabs"), a tab close-button label ("Close"), and Delete-to-close (needs an opt-in option). Happy to add any on request.

🤖 Generated with Claude Code

mathuo and others added 2 commits June 10, 2026 20:45
…Tabs pattern)

Make the tab strip operable by keyboard, completing the ARIA Tabs pattern
whose roles/states already ship:

- roving tabindex — only the active tab is in the tab order; the rest are
  reachable via arrow keys (anchored to the active tab, moves with focus)
- Arrow keys move focus along the strip (Left/Right for horizontal strips,
  Up/Down for vertical, following aria-orientation), clamped at the ends
- Home / End jump to the first / last tab
- Enter / Space activate the focused tab (manual activation — arrowing moves
  focus only, so it doesn't switch panels until committed)

The keydown handler lives on the tablist and only acts when a tab element
itself is focused, so it never hijacks keys typed inside a custom tab
renderer's own controls. Focus movement between groups and keyboard docking
are out of scope here.

Extends accessibility.spec.ts with roving-tabindex, arrow/Home/End, clamping,
manual-activation and Enter/Space coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Name the floating-group dialog (role="dialog", added previously) from its
representative group's active panel title, refreshed when the active panel
changes. An untitled panel leaves the dialog unnamed rather than hard-coding
a label string (no i18n surface).

Resolves the accessible-name gap left when the dialog role was introduced.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mathuo mathuo changed the title feat(dockview-core): keyboard navigation for the tab strip feat(dockview-core): free a11y polish — tab keyboard navigation + floating dialog name Jun 10, 2026
@mathuo mathuo changed the title feat(dockview-core): free a11y polish — tab keyboard navigation + floating dialog name feat(dockview-core): a11y polish — tab keyboard navigation + floating dialog name Jun 10, 2026
@sonarqubecloud

Copy link
Copy Markdown

@mathuo mathuo merged commit cc04a5e into master Jun 10, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant