Repository navigation
fix(hub-ui): mark the selected dock with aria-current - #475
Conversation
The dock bar and the group sidebar marked the selected dock only with a scale and a color, so a screen reader announced every dock button the same way and its user could not tell which dock was open (WCAG 4.1.2). The button of the dock that is shown now gets `aria-current="page"`. A new `isCurrent` prop carries this, because `isSelected` is also on while a group popover is merely open. Group members in the sidebar get the same attribute.
|
@erkamyaman is attempting to deploy a commit to the NuxtLabs Team on Vercel. A member of the Team first needs to authorize it. |
|
👁️🗨️ Review this pull request with grouped, summarized diffs at: raw result💭 analyzed by {
"headSha": "3a56edf266a8c641a8d16eed626946f163ca1446",
"result": {
"overallSummary": "Fixes an accessibility bug (WCAG 4.1.2) where screen readers couldn't tell which dock was selected, since it was only conveyed visually via scale/color. Adds a shared `getCurrentDockId`/`holdsCurrentDock` helper and applies `aria-current` across the dock bar, group sidebar, and the group/overflow popovers so exactly one button is marked current at a time.",
"groups": [
{
"key": "core-logic",
"label": "Current dock helper",
"summary": "Adds `getCurrentDockId()` and `holdsCurrentDock()` to decide, from the docks context, which single dock is the one currently shown (excluding actions, and none while an embedded panel is closed), and whether a group button should stand in for a hidden current member.",
"category": "core",
"filePaths": [
"packages/hub-ui/src/client/state/docks.ts"
],
"critical": true
},
{
"key": "ui-aria-current",
"label": "Apply aria-current in UI",
"summary": "Wires the new `getCurrentDockId`/`holdsCurrentDock` helpers into the dock bar, group sidebar, group popover and overflow popover so exactly one button gets `aria-current=\"page\"` (or `\"true\"` for a group/overflow button holding a hidden current dock), fixing the WCAG 4.1.2 issue where screen readers couldn't tell which dock was open.",
"category": "ui",
"filePaths": [
"packages/hub-ui/src/client/components/dock/DockEntries.vue",
"packages/hub-ui/src/client/components/dock/DockEntry.vue",
"packages/hub-ui/src/client/components/dock/DockGroupButton.vue",
"packages/hub-ui/src/client/components/dock/DockGroupPopover.vue",
"packages/hub-ui/src/client/components/dock/DockGroupSidebar.vue",
"packages/hub-ui/src/client/components/dock/DockOverflowButton.vue"
],
"fileNotes": [
{
"path": "packages/hub-ui/src/client/components/dock/DockEntry.vue",
"text": "New `current` prop distinguishes `page` (the dock actually shown) from `true` (a group/overflow button merely holding it), unlike `isSelected` which also lights up while a group popover is open."
}
]
},
{
"key": "tests",
"label": "Tests for current-dock logic",
"summary": "Unit tests covering the new helpers: selection vs. action vs. closed embedded panel, and the rule that a group is only marked current when its current member has no button of its own.",
"category": "tests",
"filePaths": [
"packages/hub-ui/src/client/state/docks.test.ts"
]
}
],
"schemaVersion": 1,
"source": "llm",
"generatedAt": "2026-11-01T12:53:35.212Z",
"model": "vercel-ai-gateway/anthropic/claude-sonnet-5",
"locale": "en"
}
} |
There was a problem hiding this comment.
🟡 Changes recommended
Outstanding accessibility issues can cause dock navigation to announce hidden or nonexistent pages as current, omit the current page, or mark multiple items as current.
4 open issues
What changed in this PR
This PR improves hub UI accessibility by marking the current dock for screen readers, separately from visual selection state.
Changes:
- Adds an
isCurrentprop that setsaria-current="page"on dock buttons. - Passes current-selection state to individual and grouped dock buttons.
- Marks selected group members in the sidebar.
| File | Description |
|---|---|
packages/hub-ui/src/client/components/dock/DockGroupSidebar.vue |
Marks the selected sidebar member as current. |
packages/hub-ui/src/client/components/dock/DockGroupButton.vue |
Passes the group's active state as isCurrent. |
packages/hub-ui/src/client/components/dock/DockEntry.vue |
Adds the isCurrent prop and ARIA attribute. |
packages/hub-ui/src/client/components/dock/DockEntries.vue |
Passes selection-based current state to dock entries. |
Review effort: Balanced
A group button now gets `aria-current="true"` and only the shown member gets `page`, so the dock bar and the group sidebar no longer both claim the current page. The group button finds the shown member among all its members, also the hidden ones. The member list of the group and overflow popover marks the shown member too, and an action dock is never current.
`aria-current` now comes from one place, `getCurrentDockId()`: the selected dock, but not an action, and not while the panel of an embedded dock is closed. Only that dock's button gets `aria-current="page"`, in the dock bar, the group sidebar or the group and overflow popover. A group button is no longer marked, so a group and its member are never both current, and `DockEntry` no longer reads `dock.type`, which its prop type does not have.
There was a problem hiding this comment.
🟡 Changes recommended
Current dock or member state can remain unannounced to screen readers for grouped and overflow entries, sidebar members, and views that remain visible after toggle actions.
4 open issues
4 resolved since last review
Review effort: Balanced
The shown dock keeps `aria-current="page"`. When it is out of sight, the button that holds it gets `aria-current="true"`: the group button of its group, the overflow button of the dock bar, or the show-more button of the group sidebar. `DockEntry` takes the value through a `current` prop.
| :is-vertical="isVertical" | ||
| :is-selected="isActive || isPanelVisible || hasActiveTool" | ||
| :is-dimmed="dimInactive && selected ? !isActive && !hasActiveTool : false" | ||
| :current="holdsCurrent ? 'true' : undefined" |
A group button was marked `aria-current="true"` even when its shown member also had a pinned or recent button on the dock bar, so the bar announced two current items. The group, and an overflow button through it, now stands in for the member only when the member has no button of its own. Tests cover `getCurrentDockId()` and `holdsCurrentDock()`.
There was a problem hiding this comment.
🟡 Changes recommended
Current-state handling can mark both a group and its selected member as current, or omit the indication for visible docks in picture-in-picture and overflow layouts.
2 open issues
3 resolved since last review
Review effort: Balanced
| const recentIds = session.recentDockIds ?? (session.recentDockId ? [session.recentDockId] : []) | ||
| return recentIds.includes(id) | ||
| || context.docks.groupedEntries.some(([, items]) => items.some(entry => entry.id === id)) |

The dock bar and the group sidebar showed the selected dock only with a scale and a color. A screen reader announced every dock button the same way, so its user could not tell which dock was open (WCAG 4.1.2).
The button of the dock whose view is shown now gets
aria-current="page", in the dock bar, the group sidebar, and the group and overflow popover. One helper,getCurrentDockId(), decides which dock that is: the selected dock, but not an action, and not while the panel of an embedded dock is closed. A group button is not marked, so a group and its member are never both current.Checks
eslinton the changed files, andtsc --noEmitinpackages/hub-uiaria-currentaria-current="page", and it moves when another dock is selected