Skip to content

Editor: refine connected document tabs and high-contrast document wells - #335605

Draft
Cherry Wang (chryw) wants to merge 17 commits into
mainfrom
dev/cherwan/agents/connected-tab-flush
Draft

Editor: refine connected document tabs and high-contrast document wells#335605
Cherry Wang (chryw) wants to merge 17 commits into
mainfrom
dev/cherwan/agents/connected-tab-flush

Conversation

@chryw

@chryw Cherry Wang (chryw) commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Continues Lee Murray (@mrleemurray)'s mrleemurray/connected-tab-exploration in a separate worktree. This is a draft design exploration, not a request to merge the final treatment yet.

Refs #331104 (selected tab is difficult to distinguish); related to the broader UI direction in #334285. I did not find an existing dedicated connected-tab PR from Lee or from this branch.

The goal is a calm, clearly selected document well: the selected tab and document body are one surface, while inactive tabs remain readable and visually subordinate. Visual Studio's observable edge and multi-row behavior informed the geometry; this does not copy its prominent accent outline into normal themes.

Visual review

Connected document tabs - typical single-row selection in Dark 2026

Typical single-row selection, Dark 2026.

Review flow: Scenario coverage -> Full OSS context -> Accessibility and consistency -> VS learnings -> Validation.

Scenario coverage

165 fixture screenshots: 11 scenarios x 15 themes. Each scenario shows every theme below. Normal wrapping uses 820px; 420px narrow and 248px edge cases are deliberate stress widths.

Connected selection

The selected tab and document form one surface; inactive tabs remain distinguishable.

Dark 2026

Dark 2026: Connected selection

Light 2026

Light 2026: Connected selection

Dark Modern

Dark Modern: Connected selection

Light Modern

Light Modern: Connected selection

Dark+

Dark+: Connected selection

Light+

Light+: Connected selection

Visual Studio Dark

Visual Studio Dark: Connected selection

Visual Studio Light

Visual Studio Light: Connected selection

Dark HC

Dark HC: Connected selection

Light HC

Light HC: Connected selection

Abyss

Abyss: Connected selection

Monokai

Monokai: Connected selection

Quiet Light

Quiet Light: Connected selection

Solarized Dark

Solarized Dark: Connected selection

Solarized Light

Solarized Light: Connected selection

First selected tab and adjacent hover

Flush left boundary and immediate neighboring hover, without an inter-tab gap.

Dark 2026

Dark 2026: First selected tab and adjacent hover

Light 2026

Light 2026: First selected tab and adjacent hover

Dark Modern

Dark Modern: First selected tab and adjacent hover

Light Modern

Light Modern: First selected tab and adjacent hover

Dark+

Dark+: First selected tab and adjacent hover

Light+

Light+: First selected tab and adjacent hover

Visual Studio Dark

Visual Studio Dark: First selected tab and adjacent hover

Visual Studio Light

Visual Studio Light: First selected tab and adjacent hover

Dark HC

Dark HC: First selected tab and adjacent hover

Light HC

Light HC: First selected tab and adjacent hover

Abyss

Abyss: First selected tab and adjacent hover

Monokai

Monokai: First selected tab and adjacent hover

Quiet Light

Quiet Light: First selected tab and adjacent hover

Solarized Dark

Solarized Dark: First selected tab and adjacent hover

Solarized Light

Solarized Light: First selected tab and adjacent hover

Inactive editor group

Selection remains identifiable when another editor group owns focus.

Dark 2026

Dark 2026: Inactive editor group

Light 2026

Light 2026: Inactive editor group

Dark Modern

Dark Modern: Inactive editor group

Light Modern

Light Modern: Inactive editor group

Dark+

Dark+: Inactive editor group

Light+

Light+: Inactive editor group

Visual Studio Dark

Visual Studio Dark: Inactive editor group

Visual Studio Light

Visual Studio Light: Inactive editor group

Dark HC

Dark HC: Inactive editor group

Light HC

Light HC: Inactive editor group

Abyss

Abyss: Inactive editor group

Monokai

Monokai: Inactive editor group

Quiet Light

Quiet Light: Inactive editor group

Solarized Dark

Solarized Dark: Inactive editor group

Solarized Light

Solarized Light: Inactive editor group

Wrapped rows - upper selection

An upper selection is a pill with the document background; normal filenames fit at 820px.

Dark 2026

Dark 2026: Wrapped rows - upper selection

Light 2026

Light 2026: Wrapped rows - upper selection

Dark Modern

Dark Modern: Wrapped rows - upper selection

Light Modern

Light Modern: Wrapped rows - upper selection

Dark+

Dark+: Wrapped rows - upper selection

Light+

Light+: Wrapped rows - upper selection

Visual Studio Dark

Visual Studio Dark: Wrapped rows - upper selection

Visual Studio Light

Visual Studio Light: Wrapped rows - upper selection

Dark HC

Dark HC: Wrapped rows - upper selection

Light HC

Light HC: Wrapped rows - upper selection

Abyss

Abyss: Wrapped rows - upper selection

Monokai

Monokai: Wrapped rows - upper selection

Quiet Light

Quiet Light: Wrapped rows - upper selection

Solarized Dark

Solarized Dark: Wrapped rows - upper selection

Solarized Light

Solarized Light: Wrapped rows - upper selection

Wrapped rows - bottom selection

Only the bottom row joins the document; row fills retain equal height.

Dark 2026

Dark 2026: Wrapped rows - bottom selection

Light 2026

Light 2026: Wrapped rows - bottom selection

Dark Modern

Dark Modern: Wrapped rows - bottom selection

Light Modern

Light Modern: Wrapped rows - bottom selection

Dark+

Dark+: Wrapped rows - bottom selection

Light+

Light+: Wrapped rows - bottom selection

Visual Studio Dark

Visual Studio Dark: Wrapped rows - bottom selection

Visual Studio Light

Visual Studio Light: Wrapped rows - bottom selection

Dark HC

Dark HC: Wrapped rows - bottom selection

Light HC

Light HC: Wrapped rows - bottom selection

Abyss

Abyss: Wrapped rows - bottom selection

Monokai

Monokai: Wrapped rows - bottom selection

Quiet Light

Quiet Light: Wrapped rows - bottom selection

Solarized Dark

Solarized Dark: Wrapped rows - bottom selection

Solarized Light

Solarized Light: Wrapped rows - bottom selection

Wrapped rows - upper hover

Hover keeps the upper pill geometry stable without changing row height.

Dark 2026

Dark 2026: Wrapped rows - upper hover

Light 2026

Light 2026: Wrapped rows - upper hover

Dark Modern

Dark Modern: Wrapped rows - upper hover

Light Modern

Light Modern: Wrapped rows - upper hover

Dark+

Dark+: Wrapped rows - upper hover

Light+

Light+: Wrapped rows - upper hover

Visual Studio Dark

Visual Studio Dark: Wrapped rows - upper hover

Visual Studio Light

Visual Studio Light: Wrapped rows - upper hover

Dark HC

Dark HC: Wrapped rows - upper hover

Light HC

Light HC: Wrapped rows - upper hover

Abyss

Abyss: Wrapped rows - upper hover

Monokai

Monokai: Wrapped rows - upper hover

Quiet Light

Quiet Light: Wrapped rows - upper hover

Solarized Dark

Solarized Dark: Wrapped rows - upper hover

Solarized Light

Solarized Light: Wrapped rows - upper hover

Compact wrapped rows

The same row/hover rules at compact density, with equal 24px row fills.

Dark 2026

Dark 2026: Compact wrapped rows

Light 2026

Light 2026: Compact wrapped rows

Dark Modern

Dark Modern: Compact wrapped rows

Light Modern

Light Modern: Compact wrapped rows

Dark+

Dark+: Compact wrapped rows

Light+

Light+: Compact wrapped rows

Visual Studio Dark

Visual Studio Dark: Compact wrapped rows

Visual Studio Light

Visual Studio Light: Compact wrapped rows

Dark HC

Dark HC: Compact wrapped rows

Light HC

Light HC: Compact wrapped rows

Abyss

Abyss: Compact wrapped rows

Monokai

Monokai: Compact wrapped rows

Quiet Light

Quiet Light: Compact wrapped rows

Solarized Dark

Solarized Dark: Compact wrapped rows

Solarized Light

Solarized Light: Compact wrapped rows

Separate pinned row

A separate pinned row retains pill shapes and the selected document surface.

Dark 2026

Dark 2026: Separate pinned row

Light 2026

Light 2026: Separate pinned row

Dark Modern

Dark Modern: Separate pinned row

Light Modern

Light Modern: Separate pinned row

Dark+

Dark+: Separate pinned row

Light+

Light+: Separate pinned row

Visual Studio Dark

Visual Studio Dark: Separate pinned row

Visual Studio Light

Visual Studio Light: Separate pinned row

Dark HC

Dark HC: Separate pinned row

Light HC

Light HC: Separate pinned row

Abyss

Abyss: Separate pinned row

Monokai

Monokai: Separate pinned row

Quiet Light

Quiet Light: Separate pinned row

Solarized Dark

Solarized Dark: Separate pinned row

Solarized Light

Solarized Light: Separate pinned row

Narrow width and icon collapse

A deliberate 420px stress case: icons yield space, while filename identity, status, and actions remain protected.

Dark 2026

Dark 2026: Narrow width and icon collapse

Light 2026

Light 2026: Narrow width and icon collapse

Dark Modern

Dark Modern: Narrow width and icon collapse

Light Modern

Light Modern: Narrow width and icon collapse

Dark+

Dark+: Narrow width and icon collapse

Light+

Light+: Narrow width and icon collapse

Visual Studio Dark

Visual Studio Dark: Narrow width and icon collapse

Visual Studio Light

Visual Studio Light: Narrow width and icon collapse

Dark HC

Dark HC: Narrow width and icon collapse

Light HC

Light HC: Narrow width and icon collapse

Abyss

Abyss: Narrow width and icon collapse

Monokai

Monokai: Narrow width and icon collapse

Quiet Light

Quiet Light: Narrow width and icon collapse

Solarized Dark

Solarized Dark: Narrow width and icon collapse

Solarized Light

Solarized Light: Narrow width and icon collapse

Right edge - automatic reveal

Normal automatic reveal in a constrained viewport keeps the complete selected action and shoulder visible.

Dark 2026

Dark 2026: Right edge - automatic reveal

Light 2026

Light 2026: Right edge - automatic reveal

Dark Modern

Dark Modern: Right edge - automatic reveal

Light Modern

Light Modern: Right edge - automatic reveal

Dark+

Dark+: Right edge - automatic reveal

Light+

Light+: Right edge - automatic reveal

Visual Studio Dark

Visual Studio Dark: Right edge - automatic reveal

Visual Studio Light

Visual Studio Light: Right edge - automatic reveal

Dark HC

Dark HC: Right edge - automatic reveal

Light HC

Light HC: Right edge - automatic reveal

Abyss

Abyss: Right edge - automatic reveal

Monokai

Monokai: Right edge - automatic reveal

Quiet Light

Quiet Light: Right edge - automatic reveal

Solarized Dark

Solarized Dark: Right edge - automatic reveal

Solarized Light

Solarized Light: Right edge - automatic reveal

Right edge - deliberate partial scrolling

Actual manual scrolling deliberately hides part of the selected tab; the remaining outline ends in a cap and curved shoulder.

Dark 2026

Dark 2026: Right edge - deliberate partial scrolling

Light 2026

Light 2026: Right edge - deliberate partial scrolling

Dark Modern

Dark Modern: Right edge - deliberate partial scrolling

Light Modern

Light Modern: Right edge - deliberate partial scrolling

Dark+

Dark+: Right edge - deliberate partial scrolling

Light+

Light+: Right edge - deliberate partial scrolling

Visual Studio Dark

Visual Studio Dark: Right edge - deliberate partial scrolling

Visual Studio Light

Visual Studio Light: Right edge - deliberate partial scrolling

Dark HC

Dark HC: Right edge - deliberate partial scrolling

Light HC

Light HC: Right edge - deliberate partial scrolling

Abyss

Abyss: Right edge - deliberate partial scrolling

Monokai

Monokai: Right edge - deliberate partial scrolling

Quiet Light

Quiet Light: Right edge - deliberate partial scrolling

Solarized Dark

Solarized Dark: Right edge - deliberate partial scrolling

Solarized Light

Solarized Light: Right edge - deliberate partial scrolling

Full OSS context

12 full-window captures, grouped by behavior rather than mixed into the opening hero. Local checkout path text is explicitly redacted; tab, outline, and layout pixels are unchanged.

Upper-row selection

Dark 2026: selected upper package.json uses the editor well background, including its action backdrop.

Dark 2026: selected upper package.json uses the editor well background, including its action backdrop.

Light 2026: selected upper package.json uses the editor well background, including its action backdrop.

Light 2026: selected upper package.json uses the editor well background, including its action backdrop.

Solarized Dark: selected upper package.json uses the editor well background, including its action backdrop.

Solarized Dark: selected upper package.json uses the editor well background, including its action backdrop.

Dark High Contrast: selected upper package.json uses the editor well background, including its action backdrop.

Dark High Contrast: selected upper package.json uses the editor well background, including its action backdrop.

Bottom-row selection and upper hover

Dark 2026: equal-height wrapped rows, upper package.json hovered, selected final-row tab connected to editor.

Dark 2026: equal-height wrapped rows, upper package.json hovered, selected final-row tab connected to editor.

Light 2026: equal-height wrapped rows, upper package.json hovered, selected final-row tab connected to editor.

Light 2026: equal-height wrapped rows, upper package.json hovered, selected final-row tab connected to editor.

Solarized Dark: equal-height wrapped rows, upper package.json hovered, selected final-row tab connected to editor.

Solarized Dark: equal-height wrapped rows, upper package.json hovered, selected final-row tab connected to editor.

Dark High Contrast: equal-height wrapped rows, upper package.json hovered, selected final-row tab connected to editor.

Dark High Contrast: equal-height wrapped rows, upper package.json hovered, selected final-row tab connected to editor.

High-contrast viewport edges: normal reveal and manual scrolling

Dark High Contrast: naturally revealed nonterminal active tab, keyboard focus ring clear of the viewport edge, close action unobstructed; no stationary clipping overlay.

Dark High Contrast: naturally revealed nonterminal active tab, keyboard focus ring clear of the viewport edge, close action unobstructed; no stationary clipping overlay.

Dark High Contrast: actual horizontal scrolling deliberately clips the active tab; opaque right-edge cap and shoulder join continuously.

Dark High Contrast: actual horizontal scrolling deliberately clips the active tab; opaque right-edge cap and shoulder join continuously.

Light High Contrast: naturally revealed nonterminal active tab, keyboard focus ring clear of the viewport edge, close action unobstructed; no stationary clipping overlay.

Light High Contrast: naturally revealed nonterminal active tab, keyboard focus ring clear of the viewport edge, close action unobstructed; no stationary clipping overlay.

Light High Contrast: actual horizontal scrolling deliberately clips the active tab; opaque right-edge cap and shoulder join continuously.

Light High Contrast: actual horizontal scrolling deliberately clips the active tab; opaque right-edge cap and shoulder join continuously.

Review follow-up

8 additional current-source captures after rebasing onto main. These supplement the scenario gallery: active multi-selection and keyboard focus in both HC themes, restored Pill custom-color fixtures, and real content-only badges under compression.

DarkHighContrast: solid inset selection stroke keeps the active multi-selected tab distinct without breaking its document well.

DarkHighContrast: solid inset selection stroke keeps the active multi-selected tab distinct without breaking its document well.

DarkHighContrast: keyboard focus replaces the solid selection ring with a dashed focus ring, without moving the tab or well.

DarkHighContrast: keyboard focus replaces the solid selection ring with a dashed focus ring, without moving the tab or well.

LightHighContrast: solid inset selection stroke keeps the active multi-selected tab distinct without breaking its document well.

LightHighContrast: solid inset selection stroke keeps the active multi-selected tab distinct without breaking its document well.

LightHighContrast: keyboard focus replaces the solid selection ring with a dashed focus ring, without moving the tab or well.

LightHighContrast: keyboard focus replaces the solid selection ring with a dashed focus ring, without moving the tab or well.

Dark Modern: explicit Pill fixtures exercise the custom modernEditorTab colors again.

Dark Modern: explicit Pill fixtures exercise the custom modernEditorTab colors again.

Dark Modern: real content-only badges retain their intrinsic width in compressed tabs.

Dark Modern: real content-only badges retain their intrinsic width in compressed tabs.

Light Modern: explicit Pill fixtures exercise the custom modernEditorTab colors again.

Light Modern: explicit Pill fixtures exercise the custom modernEditorTab colors again.

Light Modern: real content-only badges retain their intrinsic width in compressed tabs.

Light Modern: real content-only badges retain their intrinsic width in compressed tabs.

Accessibility and consistency results

Check Result and evidence
Ordinary inactive-label contrast Adjusted default-theme samples pass 4.5:1 at rest and hover; actual ratios and unchanged Solarized exceptions are listed above and in the report.
Filename identity and accessible naming under compression Regression passes for minimum basename/ellipsis/extension/badge/action space and preservation of the full filename in the tab's ARIA label.
Keyboard access to quiet actions Focus regression passes: the otherwise hidden inactive action becomes visible on focus. Selected and dirty actions remain visible.
Focus indication at the viewport edge Automatic-reveal fixture checks preserve action/focus-ring clearance; full HC OSS captures include the selected action with its keyboard focus ring. Deliberate partial scrolling is separately labeled.
HC selection and well boundary Dark/Light HC coverage verifies active/inactive-group stroke selection, a single well outline, and no content movement when themes/groups change. Active multi-selection has a solid inset ring; real keyboard-focus fixtures verify the distinct dashed ring without shifting geometry. Single/hidden-tab modes retain their card frame; configuration/enforced-mode lifecycle is covered.
Row and corner consistency Equal default/compact row heights, selected fill on every row, shared cap/shoulder radius, hover-stable geometry, and right-edge stroke alignment pass targeted regressions.
Width and responsive consistency Wide wrapping is shown at 820px; a separately labeled 420px stress case collapses icons. Wide/narrow/wide regression confirms icon recovery. Fractional-width automatic reveal and replacement selection after closing rightmost scrolled tabs are covered.
Theme/scenario coverage 15 bundled themes x 11 cases, plus 12 full OSS captures; checks include selected/hover states, multi-selection, pinned/wrapped rows, narrow widths, and viewport edges.
Existing style boundaries Tests cover connected-mode gating and restoration; classic/shared modern pill behavior and explicit foreground customization precedence remain covered. Theme-level inactive palette changes are explicitly disclosed.

Validation limits: these are targeted automated assertions and visual checks, not an end-to-end screen-reader audit or comprehensive WCAG certification. The report does not claim every customized theme, decoration color, zoom level, or keyboard workflow was tested. Full accessible labels are checked, but spoken output from individual screen readers has not been independently verified here.

Tokens, palettes, and readability

No new color ID or unrelated component-background dependency is introduced. The strip uses the semantically appropriate editorGroupHeader.tabsBackground; tab.inactiveBackground matches it. Selected fill comes from editor.background; connected inactive labels use tab.inactiveForeground rather than a blanket 50%-opacity foreground. Explicit foreground customizations continue to apply.

The eight default palettes reuse existing neutral palette values:

Theme Strip / inactive fill Ordinary inactive text contrast
Dark 2026 #202122 4.80:1
Light 2026 #EAEAEA 5.23:1
Dark Modern #2B2B2B 5.22:1
Light Modern #E5E5E5 4.92:1
Dark+ / Visual Studio Dark #303031 5.42:1
Light+ / Visual Studio Light #E8E8E8 5.05:1

These ordinary inactive-label samples meet 4.5:1 at rest and on hover in the adjusted default themes. This is not a blanket claim for every decoration, customization, or theme. The unchanged Solarized palettes remain caveats: Solarized Dark has a 4.23:1 resting sample; Solarized Light has 3.57:1 resting / 3.84:1 hover samples. They remain visible in the report rather than being silently adjusted.

Scope consideration: these palette edits are theme-level, so classic tabs also receive the updated inactive fill; Dark+/Light+ inherit the changes from their base themes. HC and the other bundled background palettes are unchanged. The connected geometry is gated; the palette changes are not.

What we leveraged from Visual Studio

VS document-tab learning Application in this exploration
The selected tab and document read as one well Continuous selected surface and connected lower contour; the selected surface color remains the same on upper rows.
Shape depends on adjacency to the document Bottom rows connect; upper wrapped and separate pinned rows use rounded pills.
Edge tabs need explicit treatment rather than ordinary interior-tab clipping A flush first edge and a curved final/viewport edge, including when scrolling.
Top and bottom curves should belong to one radius family and account for the stroke Paired caps/shoulders, shared geometry, and reserved transparent stroke space.
Actions reveal on intent Selected close and dirty status remain visible; clean inactive close appears on hover/focus.
A minimum title width protects identity; it is not the desired width for every tab Retain natural Fit sizing and use a measured compression floor rather than forcing all filenames into small tabs.

Intentional VS Code adaptations: the accent document-well border is HC-only, not a prominent active-window border in all themes. Existing VS Code tokens/palettes, settings, SCM badges, keyboard behavior, and accessible labels remain native. Filename-preserving ellipsis and icon collapse/recovery are implemented for VS Code's layout rather than transplanted as literal VS dimensions. The supplied VS behavior reference informs the design; it is not evidence that this VS Code implementation has inherited VS's validation history.

Detailed design review

Connected surface and edges

  • The selected tab uses editor.background and joins the breadcrumbs/document body. Inactive strip and tabs use editorGroupHeader.tabsBackground; there are no inter-tab gutters, so the neighboring hover begins at the active tab's end.
  • The first tab has a straight, flush left boundary. Top caps and lower shoulders use the same control-radius-plus-stroke geometry. The last tab and right viewport boundary retain the curved lower shoulder.
  • Normal automatic reveal includes the entire selected action and shoulder, with outward rounding for fractional tab widths. It is different from deliberately scrolling part of the selected tab offscreen: the latter may hide the action and uses a stationary contour to finish the visible edge.
  • Clipped contours use an opaque background fallback, meet the document separator once, and align their cap/shoulder side strokes. Separate fixtures exercise normal reveal, shoulder-only clipping, and a tab deliberately scrolled halfway offscreen.
  • Closing rightmost scrolled tabs uses the browser's clamped native offset for bounds conversion, so the replacement selection keeps its fill and HC outline.

Multi-row and pinned tabs

  • Only the bottom row connects to the body. Upper wrapped rows and a separate pinned row use rounded pills instead of detached pieces of a connected tab.
  • A selected tab always retains the document background, including on an upper row.
  • All visible row fills have the same height: 28px default / 24px compact, with spacing between rows rather than extra height or a gap under the final row.
  • Normal wrapped examples have an 820px budget and naturally sized names. Explicit compact pinned tabs keep their icon-only behavior.

Narrow widths, filenames, and actions

  • Normal fit sizing stays content-sized. The measured minimum is a compression safeguard, not a new preferred tab width.
  • Shrinking preserves the first basename character, an ellipsis, the extension, the decoration badge, and the action column. Long basenames use ellipsis rather than blunt clipping; complete names remain available through hover and accessible labels.
  • File icons collapse before filename identity is sacrificed, and return when the editor widens. A 420px Shrink-mode scenario and wide/narrow/wide regression distinguish this behavior from normal-width examples.
  • Clean inactive close actions appear on hover or keyboard focus. Selected close actions and dirty indicators remain visible. Keyboard focus and multi-selection indicators are retained.

High contrast

  • In HC only, one connected boundary outlines the selected tab and its document well: focusBorder for the active editor group and contrastBorder for other groups.
  • The duplicate outer editor-card outline is transparent, including compact-layout corner strokes.
  • Single and hidden-tab modes retain the original editor-card HC frame. Frame suppression follows the editor part's effective multiple-tab mode, including enforced options.
  • Normal themes reserve the same stroke geometry transparently, so theme/group activation does not shift content.
  • Real OSS captures complement fixture checks for the full outline, wrapping, and the right viewport edge.

Enable and review

{
  "workbench.experimental.modernUI": true,
  "workbench.experimental.modernUIEditorTabStyle": "connected"
}
  • Set the tab style to "pill" to compare the existing treatment.
  • Exercise workbench.editor.wrapTabs for multiple rows and workbench.editor.tabSizing: "shrink" for constrained widths.
  • Check active/inactive editor groups, dirty and clean tabs, keyboard focus, decorations, pinned rows, automatic reveal, and deliberate horizontal scrolling.
  • Changes apply immediately, including auxiliary editor windows. Enabling the tab-style setting alone does not enable Modern UI. Agents-window pill tabs are not switched to connected tabs.

The theme matrix covers Dark/Light 2026, Dark/Light Modern, Dark+/Light+, Visual Studio Dark/Light, Dark/Light HC, Abyss, Monokai, Quiet Light, and Solarized Dark/Light. The Component Explorer JSONC loader is expanded to support these bundled theme imports.

Validation

  • npm run transpile-client - passed on the rebased source.
  • Targeted hygiene across the complete merge-base diff - passed.
  • The tab, Modern UI, and editor utility/lifecycle suites - 96 passing.
  • Geometry/theme fixture checks: 90 fixtures / 270 rendered states, plus 45 viewport-edge fixtures / 60 states.
  • Fixture theme isolation: 5 regression cases pass in Electron, Chromium, and WebKit, including full-suite discovery in Electron and WebKit. The combined tab/theme suites pass 101 tests. Cross-theme Solarized contamination is fixed. All 30 remaining Ubuntu baseline differences were visually reviewed and reproduced with controlled old/new scope comparisons: they remove erroneous workbench backgrounds on nested editor surfaces, without geometry changes. Exact Ubuntu hashes were accepted for those corrections; contaminated Solarized baselines were not accepted.
  • Remote CI on 08c5197d5d7: Screenshots & Tests and Code OSS cross-platform build/tests pass, including Windows/macOS/Linux browser, Electron unit, integration, and smoke jobs.
  • 8 review-follow-up captures verify HC multi-selection versus keyboard focus, custom Pill colors, and intrinsic badge width. They rendered without errors; all images are included above.
  • Full report image loading, theme pixels, filtering, and native-width checks; full OSS validation for wrapped rows and normal/partial HC viewport edges.
  • git diff --check - passed.

Final targeted test invocation:

./scripts/test.sh \
  --run src/vs/workbench/test/browser/parts/editor/multiEditorTabsControl.test.ts \
  --run src/vs/workbench/contrib/modernUI/test/browser/modernUI.contribution.test.ts \
  --run src/vs/workbench/test/browser/parts/editor/editor.test.ts

The regression coverage includes dynamic icon collapse/recovery, minimum filename identity, quiet actions, sticky offsets, equal row heights, upper-row selected fill, reserved HC stroke/no layout shift, duplicate-frame removal, fractional reveal, and cap/shoulder alignment. The report contains visual evidence; it does not claim exhaustive accessibility certification.

Reviewer decisions

  • Is the restrained default strip separation sufficient without making inactive tabs too prominent?
  • Does the first/last/viewport edge geometry read consistently in normal and HC themes?
  • Are the upper-row pills and narrow icon-collapse thresholds appropriate?
  • Are the theme-level classic-tab palette changes acceptable, or should those be split from the connected-tab exploration?

Please keep this in draft while validating the design and those scope decisions.

Copilot AI balanced review requested due to automatic review settings September 11, 2026 00:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Four review findings remain, including three moderate issues and one nit.

Pull request overview

This PR refines Modern UI editor tabs with configurable pill/connected styles, connected document wells, improved sizing, theming, and high-contrast support.

Changes:

  • Adds connected-tab layout, labels, actions, and responsive sizing.
  • Adds tab-style configuration and high-contrast theme integration.
  • Expands tests, fixtures, documentation, bundled themes, and build resources.
File summaries
File Reviewed changes
src/vs/workbench/test/browser/parts/editor/multiEditorTabsControl.test.ts Layout and accessibility tests
src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts Bundled fixture theme resources
src/vs/workbench/test/browser/componentFixtures/editor/editorTabBar.fixture.ts Tab fixtures and galleries. Nit (1 vote): modernEditorTab.* colors are no longer exercised by the connected default.
src/vs/workbench/test/browser/componentFixtures/editor/editorTabBar.fixture.css Fixture state styling
src/vs/workbench/services/themes/browser/modernTabColorCustomizations.ts Theme color customization mapping
src/vs/workbench/services/layout/browser/layoutService.ts Tab-style setting constants
src/vs/workbench/contrib/modernUI/test/browser/modernUI.contribution.test.ts Contribution and theming tests
src/vs/workbench/contrib/modernUI/README.md Connected-tab documentation
src/vs/workbench/contrib/modernUI/browser/modernUI.contribution.ts Setting and window integration
src/vs/workbench/contrib/modernUI/browser/media/tabs.css Shared tab and high-contrast styling. Moderate (1 vote): the selected stroke is not restored for an active multi-selected tab.
src/vs/workbench/contrib/modernUI/browser/media/connectedEditorTabs.css Connected wells and high-contrast styling. Moderate (1 vote): the editor frame can disappear in high contrast when tabs are none or single.
src/vs/workbench/contrib/modernUI/browser/connectedEditorTabs.ts Connected surface theming
src/vs/workbench/browser/workbench.contribution.ts Tab-style setting registration
src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts Connected-tab layout and label sizing. Moderate (1 vote): badge width measurement can reserve zero space for content-only pseudo-elements.
src/vs/workbench/browser/parts/editor/media/multieditortabscontrol.css Tab fill elements
src/vs/workbench/browser/parts/editor/editorTabsControl.ts Connected-tab height handling
src/vs/workbench/browser/labels.ts Label suffix forwarding
extensions/theme-defaults/themes/light_vs.json Light classic palette updates
extensions/theme-defaults/themes/light_modern.json Light Modern palette updates
extensions/theme-defaults/themes/dark_vs.json Dark classic palette updates
extensions/theme-defaults/themes/dark_modern.json Dark Modern palette updates
extensions/theme-defaults/themes/2026-light.json Light 2026 palette updates
extensions/theme-defaults/themes/2026-dark.json Dark 2026 palette updates
build/rspack/rspack.serve-out.config.mts Theme JSON loading
build/lib/stylelint/vscode-known-variables.json Connected-tab CSS variable registration
Review details

Suppressed comments (4)

src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts:2123

  • Decoration badges are generated with content and color only, so their pseudo-element normally has no explicit width; parsing badge.width can therefore contribute 0 for the badge glyph. Because this value feeds the tab's minimum width, a fixed/shrink connected tab can let the badge consume space needed by the ellipsis or action column, breaking the identity guarantee. Measure the badge's intrinsic content (or otherwise reserve its rendered width) instead of relying only on a CSS width declaration.
			const badge = label.classList.contains('monaco-decoration-badge') ? getWindow(label).getComputedStyle(label, '::after') : undefined;
			const badgeWidth = badge ? (parseFloat(badge.width) || 0) + (parseFloat(badge.marginLeft) || 0) + (parseFloat(badge.marginRight) || 0) : 0;

src/vs/workbench/contrib/modernUI/browser/media/connectedEditorTabs.css:10

  • In high-contrast mode this hides the editor part's only frame whenever connected tabs are enabled, including workbench.editor.showTabs: "none" and "single". The replacement frame below is only emitted by selectors requiring .title.tabs (lines 28–45), so those layouts have no inner stroke and lose the contrast/focus boundary. Keep the outer HC stroke when no multi-tab title exists, or add an equivalent state class/frame for those layouts.
.modern-ui.modern-ui-connected-editor-tabs.monaco-workbench:is(.hc-black, .hc-light) .part.editor:not(.modal-editor-part) {
	border-color: transparent !important;
	--modern-ui-floating-card-stroke-color: transparent;

src/vs/workbench/contrib/modernUI/browser/media/tabs.css:825

  • In high-contrast themes the shared rule above suppresses the tab outline, but this connected branch restores contrastActiveBorder only for .selected:not(.active). An active tab that is also multi-selected therefore has only the ordinary connected well border and is visually indistinguishable from an active-only tab; include .active.multi-selected here as the non-connected branch does, or otherwise restore the selected stroke.
:is(.hc-black, .hc-light).modern-ui-tabs.monaco-workbench.modern-ui-connected-editor-tabs .part.editor > .content .editor-group-container > .title .tabs-and-actions-container .tabs-container > .tab.selected:not(.active):not(:focus) > .tab-fill,

src/vs/workbench/test/browser/componentFixtures/editor/editorTabBar.fixture.ts:779

  • These fixtures inject modernEditorTab.* colors, but renderEditorTabBarFixture now defaults editorTabStyle to connected. Connected styling intentionally replaces the active/inactive fills with the editor surface/strip colors, and modernEditorTab.activeBackground is only meaningful for pill tabs, so the ThemeColors fixtures no longer exercise the colors they are named for. Render this helper with editorTabStyle: ModernUIEditorTabStyle.Pill (or add separate connected-color coverage).
			modernUI: true,
			colorCustomizations: getModernEditorTabColorCustomizations(ctx.theme),
		});
  • Files reviewed: 25/25 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

- Added functionality to manage connected tab clipping and overflow edges in MultiEditorTabsControl.
- Introduced new CSS styles for connected editor tabs to improve visual consistency and interaction.
- Updated tests to validate the behavior of connected tabs, including clipping and overflow scenarios.
- Refactored tab rendering logic to accommodate new connected tab features and ensure proper layout.
Align the selected tab with the editor surface, move the remaining strip to the editor header background, and remove gutters at tab and row boundaries. This makes the active document well unambiguous and follows the adjacency treatment from Visual Studio and Edge.\n\nRefs #331104

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the shared pill gutters from connected editor tabs so active and inactive fills align with every strip boundary. Preserve row-specific spacing for wrapped and separate pinned rows, and keep the active surface overlapping the document well by one stroke.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Preserve filename identity and recover icons under compression, keep wrapped row heights consistent, and join the selected tab to a single HC document-well outline. Refine default strip palettes and cover bundled themes and viewport-edge states.\n\nRefs #331104

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use native scroll coordinates after tab removal clamps the viewport. Suppress the HC editor card only when the effective editor part options show multiple tabs, preserving single and hidden-tab frames.

Refs #331104

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Distinguish active multi-selection in high contrast with an inset stroke that stays inside the tab strip. Restore explicit pill-color fixtures and test intrinsic content-only badge sizing.

Refs #331104

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@chryw
Cherry Wang (chryw) force-pushed the dev/cherwan/agents/connected-tab-flush branch from e2c41fa to 66c40e9 Compare September 11, 2026 02:10
@chryw

Copy link
Copy Markdown
Contributor Author

Addressed all four findings from the review:

  1. Intrinsic badge width: verified that the flex pseudo-element exposes its rendered width through getComputedStyle (the real content-only M badge measures 9.92188px, not auto). Strengthened the minimum-width regression with a two-character WM badge and no explicit width; filename identity, badge space, and actions pass. No redundant production measurement code was needed.
  2. HC frame with single/hidden tabs: the effective tab-mode class limits outer-frame suppression to multiple-tab mode. The fix and configuration/enforced-option lifecycle tests are preserved in c447867 after the rebase.
  3. Active multi-selection in HC: added a solid inset selection ring. An ordinary bottom border would be clipped below the tab strip; the inset ring stays visible without disconnecting the document well. Real fixture checks in both HC themes verify that keyboard focus becomes dashed and geometry does not move.
  4. Custom-color fixtures: ThemeColors explicitly renders Pill tabs again, so the modernEditorTab colors are exercised.

Published the signed feedback fix in 66c40e9, rebased onto main at d20c17c, using an explicit force-with-lease.

Validation: 96 unit tests pass; full-PR scoped hygiene passes (27 paths requested, 19 checked); 135 geometry/theme fixtures cover 330 states; 8 additional review-follow-up captures render without errors. The PR description now shows 185 distinct images inline, including the new HC selection/focus, Pill-color, and intrinsic-badge evidence. Every hosted image was publicly fetched and SHA-256 verified. No collapsed image sections or report-download instructions remain.

@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Screenshot Changes

Base: 7b7e49c8 Current: f12005a8

The screenshot report exceeds GitHub's comment size limit. View the full report in the workflow summary.

Cherry Wang (chryw) and others added 3 commits September 10, 2026 20:11
Prevent additional tab themes from leaking colors into later fixtures sharing the same light or dark scheme. Cover theming participants and nested editor variables in both installation orders; retain the existing screenshot baselines.

Refs #335605

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Verify workbench-only theming does not paint nested editor scrollers. Accept 30 visually reviewed Ubuntu baselines that remove the old fixture-only background artifacts; the original Solarized contamination remains rejected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The full test suite loads Monaco CSS, so editor roots correctly use the editor background rather than transparency. Load those styles explicitly and use distinct workbench/editor colors to keep the regression independent of test discovery order while still checking nested scrollers remain transparent.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@chryw

Copy link
Copy Markdown
Contributor Author

CI fixes are verified on 08c5197. Screenshots & Tests and the complete Code OSS cross-platform run pass.

  • Fixed fixture CSS leaking between themes by scoping to the full theme identity. The 24 unintended Solarized palette changes were rejected, not accepted as baselines.
  • Reviewed and reproduced the 30 remaining Ubuntu differences: the old fixture scope incorrectly painted workbench backgrounds on nested Monaco surfaces. Accepted exact Ubuntu hashes only for those corrected artifacts; geometry is unchanged.
  • Added five theme-isolation regression cases. Made editor CSS loading explicit so the new test behaves identically alone and under full-suite discovery.
  • Local validation: 101 combined tab/theme tests; five isolation cases in Electron, Chromium, and WebKit, with full-suite discovery also checked in Electron and WebKit.

All 32 completed PR checks pass; only the separate VS Code PR Check remains pending. The PR remains draft. Its inline review retains all 185 images and now includes the final CI evidence.

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.

3 participants