Skip to content

fix(ui): keep the tab list from scrolling vertically - #500

Merged
ValentinKolb merged 2 commits into
mainfrom
fix/ui-tabs-no-vertical-scroll
Oct 1, 2026
Merged

ValentinKolb merged 2 commits into
mainfrom
fix/ui-tabs-no-vertical-scroll

Conversation

@ValentinKolb

Copy link
Copy Markdown
Collaborator

What changes

The @k2b/ui tab list no longer scrolls vertically. Before, a horizontal tab list could show a thin vertical scrollbar next to its tabs, and the selected line tab's underline was cut to 1 px. Now the list scrolls only sideways, the selected underline and the keyboard focus ring stay whole, and the list keeps exactly the same size, so nothing around it moves.

In forced-colors (high contrast) mode, the line baseline after the last tab is still drawn, in the system text color.

This answers a request from another Cloud application, where a tab bar showed a stray vertical scrollbar.

Why

.k2b-tabs__list set overflow-x: auto, which also makes overflow-y compute to auto. Line tabs overlap the list's 1 px bottom border so the selected underline can cover it, but that pixel lay outside the scrollport's padding box. The list therefore had 1 px of vertical overflow: a vertical scrollbar could appear, the underline was clipped, and the focus ring needed a 1 px deeper offset to stay visible. Two rule sets also disagreed on the scrollbar (hidden vs. thin).

How

  • The baseline is an inset box-shadow above a 1 px bottom padding instead of a bottom border. The overlap now stays inside the scrollport, and the list keeps the same height.
  • The list uses overflow: auto hidden, so it can only scroll sideways. The line-tab focus-ring offset workaround is removed.
  • The two conflicting scrollbar rule sets are merged into one thin scrollbar, which is what browsers already rendered.
  • Forced colors drop box-shadow, so the horizontal list opts out of forced colors with its border token set to CanvasText and hands its tabs back to forced colors. Pill, vertical, and PanelDialog tab lists draw no baseline and clear it the same way they cleared the border.

Documentation

docs-site/src/ui/context/actions/tabs.md now states that the list scrolls only horizontally, that the selected underline and focus ring stay whole, that the horizontal scrollbar is thin where the platform shows scrollbars, and that forced colors draw the line baseline in the system text color.

Verification

  • New packages/ui/src/actions/tabs.browser.test.ts renders line and pill lists with 3 and 24 tabs in Chromium at 1440 px and at 390 px (phone): computed overflow is auto hidden, vertical overflow is 0, the selected underline is not cut, and only the 24-tab lists scroll sideways. A forced-colors case checks the CanvasText baseline on line lists and none on pill lists.
  • Layout shift: line, pill, vertical, and PanelDialog tab lists measured in Chromium at 1440 px and 390 px with the stylesheet from main and from this branch. The bounding boxes of the tabs root, the list, the first tab, and the content after the lists are identical.
  • bun run --cwd packages/ui test: 711 tests pass, packed consumer check passes.
  • bun run check: 18/18 rules pass.
  • git diff --check is clean.

The tab list set overflow-x: auto, which also made overflow-y auto. Line
tabs overlap the list's bottom border by 1px so the selected underline
covers it, but that pixel lay outside the scrollport's padding box. The
list therefore had 1px of vertical overflow: a vertical scrollbar could
appear, the underline was clipped to 1px, and the focus ring needed a
1px deeper offset to stay visible.

The baseline is now an inset shadow above a 1px bottom padding, so the
overlap stays inside the scrollport and the list keeps exactly the same
size. The list scrolls only sideways (overflow: auto hidden), and the
line-tab focus-ring workaround is gone. The two conflicting rule sets
(hidden vs. thin scrollbar) are merged into one thin, theme-coloured
scrollbar, which is what browsers already rendered. Pill, vertical, and
PanelDialog tabs clear the new baseline the same way they cleared the
border.
Forced-colors mode drops box-shadow. Since the tab list now draws its
baseline as an inset shadow, high-contrast users lost the line after the
last tab and kept only the per-tab borders, which the old border-based
baseline did not do.

The horizontal list opts out of forced colors with its border token set to
CanvasText, so the baseline keeps the system text color, and hands its tabs
back to forced colors. A gradient background would not help: forced colors
drop gradient images too. Pill, vertical, and PanelDialog lists draw no
baseline and stay unchanged.
@ValentinKolb
ValentinKolb enabled auto-merge October 1, 2026 03:51
@ValentinKolb
ValentinKolb added this pull request to the merge queue Oct 1, 2026
Merged via the queue into main with commit fac3137 Oct 1, 2026
17 checks passed
@ValentinKolb
ValentinKolb deleted the fix/ui-tabs-no-vertical-scroll branch October 1, 2026 04:12
@github-actions github-actions Bot mentioned this pull request Oct 1, 2026
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