Skip to content

fix(a11y): filter hidden nav items in mobile bottom-nav (WCAG 4.1.2)#3494

Merged
ardiewen merged 3 commits into
mainfrom
a11y/4.1.2-bottom-nav-hidden-flag
Jun 4, 2026
Merged

fix(a11y): filter hidden nav items in mobile bottom-nav (WCAG 4.1.2)#3494
ardiewen merged 3 commits into
mainfrom
a11y/4.1.2-bottom-nav-hidden-flag

Conversation

@ardiewen

@ardiewen ardiewen commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

The mobile bottom-nav drawer renders NavigationItems directly inside +layout.svelte's linksSnippet, bypassing NavSection's !item.hidden filter. As a result, capability-gated nav links still render as focusable links for keyboard and screen-reader users on servers that don't support them:

  • Standalone Activitieshidden when the server is < 1.30.0
  • Nexushidden when systemInfo.capabilities.nexus is absent

The desktop side-nav already hides these correctly (it routes through NavSection), so this is a mobile-only regression.

Root cause — interaction of two prior PRs

So the hidden flag (set at +layout.svelte for Activities/Nexus) was being ignored on the mobile bottom nav.

Fix

Apply the same !item.hidden predicate NavSection uses to both bottom-nav groups:

- {#each linkList as link, i (i)}
+ {#each linkList.filter((item) => !item.hidden) as link, i (i)}
    <NavigationItem {...link} link={link.href} />
  {/each}

  <hr class="border-subtle" />

- {#each linkListForSecondGroup as link, i (i)}
+ {#each linkListForSecondGroup.filter((item) => !item.hidden) as link, i (i)}
    <NavigationItem {...link} link={link.href} />
  {/each}

The static feedback item in the side-nav bottom() snippet has no hidden flag and is unaffected.

Note on overlap with #3441: that PR also edits this same linksSnippet (reordering for WCAG 1.3.2). The two changes are independent but touch the same lines, so whichever merges second will resolve to the combined form, e.g. [...linkList].filter((item) => !item.hidden).reverse().

Test plan

  • On a Temporal server lacking Nexus capability: open the mobile bottom-nav drawer (DevTools device mode) — the Nexus link should not appear, and should not be reachable via Tab or screen reader.
  • On a server < 1.30.0: the Standalone Activities link should not appear in the bottom-nav drawer.
  • On a fully-capable server: all nav links still appear (no over-filtering).
  • Desktop side-nav behavior is unchanged.

A11y-Audit-Ref: 4.1.2-nav-hidden-flag-ignored

🤖 Generated with Claude Code

@ardiewen
ardiewen requested a review from a team as a code owner June 3, 2026 18:53
@vercel

vercel Bot commented Jun 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
holocene Ready Ready Preview, Comment Jun 4, 2026 1:59pm

Request Review

ardiewen and others added 2 commits June 4, 2026 09:46
The mobile bottom-nav linksSnippet renders NavigationItem directly,
bypassing NavSection's `!item.hidden` filter. As a result, capability-
gated links (Standalone Activities on server <1.30.0, Nexus when
systemInfo.capabilities.nexus is absent) still rendered as focusable
links for keyboard and screen-reader users on incapable servers — the
desktop side-nav already filters these via NavSection.

This gap was introduced when #3445 flattened NavSection into a snippet of
raw NavigationItems; #3434 added the hidden filter to NavSection only.
Apply the same `!item.hidden` predicate to both bottom-nav groups.

A11y-Audit-Ref: 4.1.2-nav-hidden-flag-ignored

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Add a mobile integration spec verifying the bottom-nav drawer hides
capability-gated links from keyboard/AT users:
- Nexus hidden when systemInfo.capabilities.nexus is false, shown when true
- Standalone Activities hidden on server < 1.30.0, shown on >= 1.30.0

Uses the existing mockClusterApi / mockSystemInfoApi route mocks to drive
the serverVersion and capabilities the gates depend on. Verified the two
"hides" cases fail without the filter fix (genuine regression guard).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
The conflict resolution for the #3441/#3494 merge left the combined
[...group].filter(...).reverse() each-expressions unformatted; rebase
--continue does not run the lint-staged pre-commit hook. Apply prettier.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@ardiewen
ardiewen merged commit 99f0a0a into main Jun 4, 2026
16 checks passed
@ardiewen
ardiewen deleted the a11y/4.1.2-bottom-nav-hidden-flag branch June 4, 2026 15:00
rossedfort added a commit that referenced this pull request Jun 4, 2026
Auto-generated version bump from 2.50.0 to 2.51.0

Bump type: minor

Changes included:
- [`495e27f7`](495e27f) Use pageSize instead of maximumPageSize (#3422)
- [`42c58c45`](42c58c4) fix: use rem-based width for expanded side-nav (#3426)
- [`ce928ed5`](ce928ed) fix(a11y): meet 4.5:1 contrast for text-subtle and text-warning (WCAG 1.4.3) (#3437)
- [`e8ed8a49`](e8ed8a4) fix(a11y): consistent high-contrast focus rings across all Button variants (WCAG 1.4.11) (#3438)
- [`03918fb5`](03918fb) fix(a11y): prevent horizontal scroll on login page at 320px (WCAG 1.4.10) (#3440)
- [`a11555fb`](a11555f) fix(a11y): use rem-based font-size and unitless line-height in markdown reset (#3430)
- [`057ff323`](057ff32) fix: use empty alt on decorative SDK logo image (#3424)
- [`e435ffd7`](e435ffd) Standalone Activity details page UI updates (#3427)
- [`e09028f3`](e09028f) Make bottom-nav accept linksSnippet instead of sections (#3445)
- [`a22a1e21`](a22a1e2) Add tooltip for SDK version (#3462)
- [`c3b7820e`](c3b7820) [DT-4039] Workflow query builder doesn't work with numeric search attributes (#3435)
- [`5e53881f`](5e53881) Make Common Errors dismissable (#3471)
- [`2665e2f1`](2665e2f) [DT-4048] Add accessibility PR triage and notification helpers (#3465)
- [`8083cf4e`](8083cf4) feat(DT-4017): Schedules List UI Update (#3467)
- [`b5de30e3`](b5de30e) fix(markdown): allow nested lists to render as block (DT-4047) (#3463)
- [`8a6fd2de`](8a6fd2d) Add a prop to hide select/deselect controls (#3474)
- [`33ec1b3e`](33ec1b3) DT-4051: pre-populate input when starting standalone activity like this one (#3469)
- [`0d64fc20`](0d64fc2) fix(a11y): reveal Copyable's CopyButton on focus-within (WCAG 2.1.1) (#3452)
- [`321651c0`](321651c) fix: accept autocomplete prop on NumberInput, ChipInput, and Combobox (#3425)
- [`6567c222`](6567c22) fix: cap ZoomSvg container height to viewport (#3428)
- [`afd3a8ed`](afd3a8e) fix(a11y): accommodate text-spacing overrides on Badge and Chip (WCAG 1.4.12) (#3433)
- [`d264b876`](d264b87) fix(a11y): non-color signal for Label required indicator (WCAG 1.4.1) (#3439)
- [`73c61ea3`](73c61ea) fix(a11y): tabindex on <main> so the skip link moves focus reliably (WCAG 2.4.1) (#3451)
- [`34e582a8`](34e582a) fix(a11y): info-and-relationships compliance (WCAG 1.3.1) (#3432)
- [`f7be7b6c`](f7be7b6) fix(query): quote ExecutionDuration Go duration strings in visibility SQL (#3482)
- [`9f0c2631`](9f0c263) Passthrough goto params to link component (#3483)
- [`2f8c037b`](2f8c037) feat: add centerButton, menuButton, and linksContent snippets to BottomNavigation (#3485)
- [`7f258bac`](7f258ba) fix: add "for" to validate connection modal title (#3488)
- [`350397ab`](350397a) feat(DT-4069): Update modal backdrop to 50% opaque (#3486)
- [`f01baa49`](f01baa4) refactor: Input & DatePicker - Svelte 5 & afterLabel snippet (#3479)
- [`587c892f`](587c892) Fix decoded object payload summaries (#3491)
- [`2b85ef06`](2b85ef0) fix(DT-4044): only use browser codec endpoint when override option is selected (#3490)
- [`468893ba`](468893b) fix(a11y): improve 1.1.1 non-text content compliance (#3431)
- [`3e8c996d`](3e8c996) fix(a11y): make Tooltip keyboard-accessible, dismissible, and hoverable (#3429)
- [`47552538`](4755253) fix(a11y): name-role-value compliance, partial (WCAG 4.1.2) (#3434)
- [`e2c95d54`](e2c95d5) fix(a11y): align DOM order with visual order in mobile bottom-nav (WCAG 1.3.2) (#3441)
- [`634b08e1`](634b08e) a11y(1.4.11): focus rings — lighten dark-mode --color-border-focus-info to indigo.400 so ring-primary/70 meets 3:1 against surface-primary (#3478)
- [`039a555a`](039a555) a11y(1.4.11): Checkbox — add ring-offset so the checked-state focus ring contrasts against the indigo checked background (#3477)
- [`01161e2e`](01161e2) a11y(1.4.10): activity-options drawer — make width responsive so it reflows at 320 px (#3476)
- [`99f0a0a4`](99f0a0a) fix(a11y): filter hidden nav items in mobile bottom-nav (WCAG 4.1.2) (#3494)
- [`d12ebacc`](d12ebac) fix(a11y): add focusin/focusout to saved-query nav hover tooltip (WCAG 2.1.1) (#3453)
- [`c7206af9`](c7206af) fix(a11y): render a warning icon for Chip warning intent (WCAG 1.4.1) (#3450)
- [`b64ed713`](b64ed71) fix(a11y): pair Toast variant background with a severity icon (WCAG 1.4.1) (#3449)
- [`8e2ef708`](8e2ef70) upgrade temporal api version to latest (v1.62.13) (#3502)

Co-authored-by: rossedfort <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a11y:bucket-3 Bucket 3: engineer required a11y:sc-4.1.2 a11y Accessibility audit PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants