XS✔ ◾ Fix #785: make the Settings nav scrollbar visible across OSes#987
XS✔ ◾ Fix #785: make the Settings nav scrollbar visible across OSes#987tomek-i wants to merge 1 commit into
Conversation
The Settings side-nav already scrolled mechanically (fixed in #803 via overflow-y-auto + min-h-0), but it relied on the OS/browser's native scrollbar. That scrollbar can render with zero visible width (observed here on Linux/GTK themes) or stay hidden until actively scrolled (macOS default), leaving no visual cue that more tabs exist below the fold — even though wheel/trackpad scrolling already worked. Wrap the tablist in the same ScrollArea (Radix) component the settings panel already uses, with type="auto" so its styled scrollbar thumb renders immediately whenever the list overflows (no hover/scroll needed to discover it), and is absent when everything fits. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
PR Metrics✔ Thanks for keeping your pull request small.
Metrics computed by PR Metrics. Add it to your Azure DevOps and GitHub PRs! |
There was a problem hiding this comment.
Pull request overview
This PR addresses Settings side-nav scrollbar discoverability across operating systems by replacing the nav’s native overflow-y-auto scrolling container with the app’s shared Radix-based ScrollArea, ensuring a consistently visible scrollbar when the list actually overflows (per #785).
Changes:
- Wrap the Settings nav
tablistin the sharedScrollAreawithtype="auto"to provide a styled, cross-OS-consistent scrollbar when needed. - Adjust the nav’s internal layout classes to suit the
ScrollAreawrapper. - Add a UI unit regression test asserting the
tablistis rendered inside theScrollAreaviewport/root.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/ui/src/components/settings/SettingsNav.tsx | Replaces the native overflow scrolling container with the shared ScrollArea wrapper for consistent scrollbar visibility across OSes. |
| src/ui/src/components/settings/SettingsNav.test.tsx | Adds a structural regression test ensuring the tablist remains inside the ScrollArea wrapper. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
🚀 Pre-release build is available for this PR: |
|
🔭 crows-nest: ready-PR pipeline started — review → address → re-validate → gated merge. |
muster review — PR #987Status: single-lens / degraded — the Lens A — code-review (conventions + correctness)Reviewed the diff ( Findings: none (no blocking, major, minor, or nit issues). ARIA semantics ( Lens B — codex-rescue (independent second opinion)Did not run — agent type unavailable in this environment. No second opinion was obtained. Bottom line0 blocking, 0 major, 0 minor, 0 nit — no blocking findings from the one lens that ran, but this is a degraded (single-lens) review, not a full green light. Recommend a human or a future muster pass with the codex-rescue lens available before treating this as fully inspected. |
|
🔭 crows-nest: blocked — review degraded (codex-rescue second-opinion lens unavailable in this environment; only the code-review lens ran, which found 0 blocking/major/minor/nit issues — a degraded review is treated as not-safe, never as a clean pass) and branch protection not yet satisfied (required review approval pending, mergeStateStatus=BLOCKED). Needs a human to: (1) approve the required review, and (2) optionally re-run muster once the codex-rescue lens is available for a full second-opinion pass. |
Summary
The Settings side-nav list already scrolled mechanically (fixed in #803 via
overflow-y-auto+min-h-0), but relied on the OS/browser's native scrollbar to signal that. That scrollbar can render with effectively zero visible width or stay hidden until actively scrolled, so at a reduced window height the list looked clipped with no indication more tabs existed below the fold — matching the symptom in this issue's video/screenshot. This PR wraps the nav in the same styledScrollAreacomponent the settings content panel already uses, withtype="auto", so a visible scrollbar thumb renders immediately whenever the list overflows, consistently across OSes.Closes #785
Requested by: @griffenedge
What changed
src/ui/src/components/settings/SettingsNav.tsxrole="tablist"nav in the sharedScrollArea/ScrollBar(Radix) component,type="auto", instead of a bareoverflow-y-autodiv. Preserves the existingmin-h-0flex-shrink behavior, roving-tabindex keyboard nav, and focus-follow logic from #803 unchanged.src/ui/src/components/settings/SettingsNav.test.tsxscroll-area-viewport/scroll-area(guards against a future refactor silently dropping the wrapper).Decisions
ScrollAreaUI component (already used by the settings content panel) rather than styling the native scrollbar with custom CSS (e.g.::-webkit-scrollbar).ScrollAreaalready ships in the project's dependencies.::-webkit-scrollbarstyling — rejected because it's WebKit/Blink-only and wouldn't guarantee visibility in the packaged Electron/Chromium runtime the same way as an explicitly-rendered scrollbar element, and would duplicate styling already defined for the panel'sScrollArea.type="auto"(renders only while content actually overflows) rather thantype="always"(always rendered, even with nothing to scroll).type="hover"— rejected; it only mounts the scrollbar on pointer hover/scroll and auto-hides again, which is the same discoverability gap this issue reports (no persistent visual affordance that the list is scrollable).Acceptance criteria
overflow/min-h-0behavior preserved), reverified via Playwright at 220/250/300px window heights.mouse.wheel);scrollTopadvances and the target tab becomes reachable.ScrollAreascrollbar thumb renders immediately (no hover needed) whenever the list overflows, and is absent when content fits (no unnecessary UI).Testing
SettingsNav.test.tsx— new#785describe block; all 8 tests in the file pass)npm run buildat root, andnpm run buildinsrc/ui)npx vitest run --exclude 'src/ui/**'— 696/696 backend tests;src/uivitest — 262/262 UI tests)npm run lint,npm run format— no diffs, no errors)No pre-existing failures were encountered on the base branch during validation.
Bug repro evidence
SettingsDialog/SettingsNavcomponent tree (with the project's actual Tailwind build) in the Vite dev server and drove it with headless Chromium (Playwright) at reduced viewport heights (300px/250px/220px), inspecting the rendered DOM for[data-slot="scroll-area-scrollbar"]and measuringscrollHeight/clientHeight/scrollTopbefore and after a synthesized mouse-wheel event.scrollHeight: 364vsclientHeight: 163,canScroll: true), andscrollTopdoes move to201after a wheel event — but zero scrollbar-related elements exist in the DOM (nativeoverflow-y-autorenders whatever the OS/browser default scrollbar is — in this Linux/Chromium environment, effectively invisible:offsetWidth - clientWidth === 0). Screenshots taken before/after the wheel scroll show no scrollbar track/thumb anywhere in the nav column.[data-slot="scroll-area-scrollbar"]element is present in the DOM,isVisible(): true, with a real bounding box ({width: 10, height: 162.5}) rendered immediately (no hover/scroll interaction required to appear) whenever the list overflows — and disappears when the window is tall enough that all 8 tabs already fit (500px height → 0 scrollbar elements, correctly). Wheel-scroll and keyboard (Home/End/Arrow, from the 🐛 Bug - Settings options list cannot scroll and arrow keys do not navigate #803 roving-tabindex) navigation both still correctly movescrollTopand bring the target tab fully into view.Screenshots
Captured locally during automated verification (headless Chromium, 250px viewport height) — not attached to this PR body, but the DOM/behavioral evidence above was captured from the same runs.
Follow-up items
🤖 Generated with Claude Code