Editor: refine connected document tabs and high-contrast document wells - #335605
Editor: refine connected document tabs and high-contrast document wells#335605Cherry Wang (chryw) wants to merge 17 commits into
Conversation
There was a problem hiding this comment.
🔵 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
contentand color only, so their pseudo-element normally has no explicitwidth; parsingbadge.widthcan 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
contrastActiveBorderonly 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-selectedhere 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, butrenderEditorTabBarFixturenow defaultseditorTabStyletoconnected. Connected styling intentionally replaces the active/inactive fills with the editor surface/strip colors, andmodernEditorTab.activeBackgroundis only meaningful for pill tabs, so theThemeColorsfixtures no longer exercise the colors they are named for. Render this helper witheditorTabStyle: 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.
…verage for connected tabs
…roved surface handling
…riable handling for improved UI consistency
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>
e2c41fa to
66c40e9
Compare
|
Addressed all four findings from the review:
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. |
Screenshot ChangesBase: The screenshot report exceeds GitHub's comment size limit. View the full report in the workflow summary. |
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>
|
CI fixes are verified on 08c5197. Screenshots & Tests and the complete Code OSS cross-platform run pass.
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. |
Summary
Continues Lee Murray (@mrleemurray)'s
mrleemurray/connected-tab-explorationin 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
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
Light 2026
Dark Modern
Light Modern
Dark+
Light+
Visual Studio Dark
Visual Studio Light
Dark HC
Light HC
Abyss
Monokai
Quiet Light
Solarized Dark
Solarized Light
First selected tab and adjacent hover
Flush left boundary and immediate neighboring hover, without an inter-tab gap.
Dark 2026
Light 2026
Dark Modern
Light Modern
Dark+
Light+
Visual Studio Dark
Visual Studio Light
Dark HC
Light HC
Abyss
Monokai
Quiet Light
Solarized Dark
Solarized Light
Inactive editor group
Selection remains identifiable when another editor group owns focus.
Dark 2026
Light 2026
Dark Modern
Light Modern
Dark+
Light+
Visual Studio Dark
Visual Studio Light
Dark HC
Light HC
Abyss
Monokai
Quiet Light
Solarized Dark
Solarized Light
Wrapped rows - upper selection
An upper selection is a pill with the document background; normal filenames fit at 820px.
Dark 2026
Light 2026
Dark Modern
Light Modern
Dark+
Light+
Visual Studio Dark
Visual Studio Light
Dark HC
Light HC
Abyss
Monokai
Quiet Light
Solarized Dark
Solarized Light
Wrapped rows - bottom selection
Only the bottom row joins the document; row fills retain equal height.
Dark 2026
Light 2026
Dark Modern
Light Modern
Dark+
Light+
Visual Studio Dark
Visual Studio Light
Dark HC
Light HC
Abyss
Monokai
Quiet Light
Solarized Dark
Solarized Light
Wrapped rows - upper hover
Hover keeps the upper pill geometry stable without changing row height.
Dark 2026
Light 2026
Dark Modern
Light Modern
Dark+
Light+
Visual Studio Dark
Visual Studio Light
Dark HC
Light HC
Abyss
Monokai
Quiet Light
Solarized Dark
Solarized Light
Compact wrapped rows
The same row/hover rules at compact density, with equal 24px row fills.
Dark 2026
Light 2026
Dark Modern
Light Modern
Dark+
Light+
Visual Studio Dark
Visual Studio Light
Dark HC
Light HC
Abyss
Monokai
Quiet Light
Solarized Dark
Solarized Light
Separate pinned row
A separate pinned row retains pill shapes and the selected document surface.
Dark 2026
Light 2026
Dark Modern
Light Modern
Dark+
Light+
Visual Studio Dark
Visual Studio Light
Dark HC
Light HC
Abyss
Monokai
Quiet Light
Solarized Dark
Solarized Light
Narrow width and icon collapse
A deliberate 420px stress case: icons yield space, while filename identity, status, and actions remain protected.
Dark 2026
Light 2026
Dark Modern
Light Modern
Dark+
Light+
Visual Studio Dark
Visual Studio Light
Dark HC
Light HC
Abyss
Monokai
Quiet Light
Solarized Dark
Solarized Light
Right edge - automatic reveal
Normal automatic reveal in a constrained viewport keeps the complete selected action and shoulder visible.
Dark 2026
Light 2026
Dark Modern
Light Modern
Dark+
Light+
Visual Studio Dark
Visual Studio Light
Dark HC
Light HC
Abyss
Monokai
Quiet Light
Solarized Dark
Solarized Light
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
Light 2026
Dark Modern
Light Modern
Dark+
Light+
Visual Studio Dark
Visual Studio Light
Dark HC
Light HC
Abyss
Monokai
Quiet Light
Solarized Dark
Solarized Light
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.
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.
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.
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.
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: 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: 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: 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: 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: real content-only badges retain their intrinsic width in compressed tabs.
Light Modern: explicit Pill fixtures exercise the custom modernEditorTab colors again.
Light Modern: real content-only badges retain their intrinsic width in compressed tabs.
Accessibility and consistency results
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.inactiveBackgroundmatches it. Selected fill comes fromeditor.background; connected inactive labels usetab.inactiveForegroundrather than a blanket 50%-opacity foreground. Explicit foreground customizations continue to apply.The eight default palettes reuse existing neutral palette values:
#202122#EAEAEA#2B2B2B#E5E5E5#303031#E8E8E8These 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
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
editor.backgroundand joins the breadcrumbs/document body. Inactive strip and tabs useeditorGroupHeader.tabsBackground; there are no inter-tab gutters, so the neighboring hover begins at the active tab's end.Multi-row and pinned tabs
Narrow widths, filenames, and actions
fitsizing stays content-sized. The measured minimum is a compression safeguard, not a new preferred tab width.High contrast
focusBorderfor the active editor group andcontrastBorderfor other groups.Enable and review
{ "workbench.experimental.modernUI": true, "workbench.experimental.modernUIEditorTabStyle": "connected" }"pill"to compare the existing treatment.workbench.editor.wrapTabsfor multiple rows andworkbench.editor.tabSizing: "shrink"for constrained widths.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.08c5197d5d7: Screenshots & Tests and Code OSS cross-platform build/tests pass, including Windows/macOS/Linux browser, Electron unit, integration, and smoke jobs.git diff --check- passed.Final targeted test invocation:
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
Please keep this in draft while validating the design and those scope decisions.