Repository navigation
fix(app-shell): the icon-mode sidebar rail scrolls vertically when its rows overflow (objectui#12794) - #12846
Conversation
In the collapsed (icon-mode) sidebar the SidebarContent primitive clips with a variant-scoped overflow-hidden, so rows below the fold could not be reached until the sidebar expanded (objectui#12794). UnifiedSidebar passes the same variant with overflow-auto (which tailwind-merge lets replace the primitive's shorthand) plus overflow-x-hidden, and hides the rail's scrollbar so a classic bar does not take its width out of the 3rem rail. Off icon mode the class list is unchanged. Claude-Session: https://claude.ai/code/session_0129XjRmiNNiNRzQ5twZ75Vr Co-authored-by: Claude <noreply@anthropic.com>
席位核对 — ACCEPT · objectui#12794 · head
|
| reading | before | after |
|---|---|---|
| rows below the fold | 29 of 49 | 29 of 49 |
scrollTop after one wheel |
0 | 400 |
scrollTop at the end |
0 | 1165 |
| the last row | unreachable | reachable, hit-testable, navigates on click |
rail width (offsetWidth / clientWidth) |
47 / 47 | 47 / 47 |
Screenshots, read by the seat (never-merged claude/issue-12794-evidence at 98855b6):
- icon rail scrolled to its last row (Renewals Pipeline), light and dark: icons centred, no scrollbar;
- expanded sidebar, light (CONTROL).
Sent to the maintainer at 2026-10-17T02:26Z.
Tests:
- New
UnifiedSidebar.iconRailScroll-12794.test.tsxthrough the realUnifiedSidebarand the real primitives. It derives the icon-mode prefix from the primitive's own token, so a drift in the primitive fails loudly. Collapsed: the three classes are present and no icon-modeoverflow-hiddensurvives. CONTROL: the expanded list equals the bare primitive's. - Three ablations, each red, each restored to an empty
git diff HEAD. - The full app-shell suite in 8 shards: 1,512 files, 14,120 tests passed, 0 failed.
type-check,build, eslint on touched files (0 errors), the i18n checks, changeset presence and line citations: all exit 0.
Changeset: @object-ui/app-shell patch; user-facing prose.
CI: running at this record. Landing waits for green.
Rulings
- Scrollbar treatment: A, as built. The bar is hidden in icon mode only. Reachability is the measured defect, wheel, touch and focus still scroll, and the cut-off rows at the rail's edge show there is more.
packages/layout'sAppSchemaRenderericon rail: read from source and not measured, so not filed under the contract. It is noted in the PR's acceptance notes.- The sharded full suite: accepted. A single unsharded app-shell run cannot finish inside the container's limits.
- The contract conflict: as dispatched. The relay is refused from the dev's container, so the seat opened the PR and relayed the report.
- objectui#12795 (the keyboard half, same file) lands after this PR.
Implemented-by: cloud session session_0129XjRmiNNiNRzQ5twZ75Vr, branch claude/issue-12794-icon-rail-scroll
Generated by Claude Code
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Landing · head
|
Fixes #12794
Clause-②: no
What changed
In the collapsed (icon-mode) console sidebar the rail now scrolls vertically when its rows overflow, as the expanded sidebar does. Before, the rows below the fold could not be reached until the sidebar was expanded again.
The
SidebarContentprimitive clips the rail withgroup-data-[state=collapsed]:group-data-[collapsible=icon]:overflow-hidden.UnifiedSidebarnow passes one class constant,ICON_RAIL_SCROLLS_VERTICALLY, which sits beside the objectui#12744 constant and uses the same icon-mode variant:overflow-auto: tailwind-merge (cn) drops the primitive's same-variantoverflow-hiddenonly for a later same-variantoverflow-*shorthand. Measured: with onlyoverflow-y-auto/overflow-x-hidden, both the primitive'soverflow-hiddenand the longhands survive the merge, and stylesheet order decides the result. So the shorthand is the pin.overflow-x-hidden: the horizontal axis stays clipped (the rail's content is 109px wide in a 47px rail) and the rail never scrolls sideways.[scrollbar-width:none]!: the rail draws no scrollbar. With the console's thin bar visible, the rail's clientWidth drops from 47 to 37, the 32px buttons run under the bar, and the icons sit 5.5px off the scroll box's centre. The class is important because the console themes every scrollbar with an unlayered*rule, which outranks layered utilities. The wheel, touch and keyboard focus still scroll the rail.Off icon mode nothing changes: the expanded sidebar and the mobile sheet keep the primitive's
overflow-autoand the host's scrollbar.packages/components/src/ui/sidebar.tsx(Shadcn-synced) is untouched. No export, prop, type member or i18n key moves.Live readings
Chromium at 1280 x 800, objectstack
examples/app-showcase(objectstack dev --fresh), console Vite from this worktree. Icon mode with every group opened, collapsed with Ctrl+B, starting at scrollTop 0. Visible-scrollbar readings run without Playwright's default--hide-scrollbars.4839f5cb1c05f1Screenshots (evidence branch
claude/issue-12794-evidence, not merged here):Tests (at
b1c05f1)UnifiedSidebar.iconRailScroll-12794.test.tsxmounts the realUnifiedSidebarwith the realSidebarProvider/Sidebar/SidebarContent, using the harness of the objectui#12744 test. It derives the icon-mode prefix from the bare primitive's own:overflow-hiddentoken. Collapsed: the content has the variant'soverflow-auto,overflow-x-hiddenand[scrollbar-width:none]!, and no icon-modeoverflow-hidden,overflow-y-hiddenor clip survives. CONTROL, expanded: every class outside the variant equals the bare primitive's list with the oldpt-2.git diff HEADempty: (A) call site back topt-2turns the collapsed test red; (B) shorthand swapped foroverflow-y-autoturns it red, which is the merge trap above; (C) an unconditionaloverflow-x-hiddenturns both tests red.@object-ui/app-shellin full, aspnpm exec vitest run packages/app-shell/ --shard=K/8for K = 1..8: 1512 of 1512 files, 1511 passed and 1 skipped; 14120 tests passed, 9 skipped, 0 failed. A single unsharded run cannot finish inside the container's command limits.type-check,buildand eslint on the touched files for@object-ui/app-shell: exit 0 (lint warnings all predate this diff).check:i18n-keys,check:i18n-drift,check-changeset-presence,check:new-line-citations: exit 0.Acceptance notes
packages/layoutAppSchemaRenderer.tsxalso rendersSidebar collapsible="icon"with a bareSidebarContent, andAppShellforwardsdefaultOpen. Read from source only and not measured: a publishedAppSchemaRenderercollapsed to icons may clip its rail the same way. The dispatch ruled thepackages/layoutsidebars out of scope, so this PR does not touch them. No carrier.Session:
https://claude.ai/code/session_0129XjRmiNNiNRzQ5twZ75VrGenerated by Claude Code