Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
f08bdc8
init: basic layout for tab strip
thenhnn Sep 14, 2025
d45c0ac
feat: basic tabs layout
thenhnn Sep 14, 2025
ff62d86
feat: actually working tab strip, but without dnd
thenhnn Sep 15, 2025
04322ec
fix: show tab bubble to left when vertical tabs are enabled
thenhnn Sep 15, 2025
d1b794c
fix: working DND!
thenhnn Sep 17, 2025
d5136b4
fix: split patches
thenhnn Sep 21, 2025
2fb82b1
fix: tab groups
thenhnn Sep 21, 2025
f404919
fix: tab groups
thenhnn Sep 22, 2025
3ab7123
fix: offset contents container so dialogs are positioned properly
thenhnn Sep 24, 2025
ddb2b19
fix: change corner radius of split view tabs
thenhnn Sep 25, 2025
3a62375
fix: make macOS traffic lights position properly
thenhnn Sep 26, 2025
7858bf0
fix: make fullscreen work properly
thenhnn Sep 27, 2025
f68e1de
fix: remove debug log
thenhnn Sep 27, 2025
f04be15
patches: refresh
thenhnn Oct 2, 2025
dbb643e
fix compilation
thenhnn Oct 3, 2025
097f5a8
fix: make split tabs look better, add top padding for tabs
thenhnn Oct 5, 2025
8143626
fix: open tabs to the right when vertical tabs are enabled
thenhnn Oct 5, 2025
e3686fa
refresh
thenhnn Oct 7, 2025
7fb91ca
helium/ui/vertical-tabs: add a proper feature flag
wukko Oct 9, 2025
2412c44
merge: helium 0.5.5 from upstream
wukko Oct 9, 2025
348235e
helium/ui/layout-constants: refactor to eliminate duplication
wukko Oct 9, 2025
8d93ee5
helium/ui/vertical-tabs: fix tab "ripping out", reposition toolbar
wukko Oct 9, 2025
d79cb74
helium/ui/vertical-tabs: fix vertical tabs' top offset
wukko Oct 9, 2025
21e689c
helium/ui/vertical-tabs: fix screwed up formatting
wukko Oct 9, 2025
24397dd
helium/ui/vertical-tabs: fix visuals, add new tab button
wukko Oct 9, 2025
3ab6709
fix conflict
thenhnn Oct 18, 2025
5f37e8d
patches: refresh vertical-tabs/feature-flag.patch
thenhnn Oct 18, 2025
3254689
feat: add unpin button (doesn't allow to unpin buttons yet)
thenhnn Oct 19, 2025
1dd1654
fix: offset title so it doesnt overlap with unpin button
thenhnn Oct 19, 2025
e4578b8
fix: background on linux
thenhnn Oct 19, 2025
d21ff1e
helium/ui/vertical-tabs: split ui.patch into smaller patches
wukko Oct 21, 2025
8858ac7
helium/ui/vertical-tabs: unpin button func, fix stuck "unpinning" state
wukko Oct 21, 2025
a25ddb5
helium/ui/vertical-tabs: add tab search button
wukko Oct 21, 2025
49bc80e
helium/ui/vertical-tabs: add new tabs to the start of the tab strip
wukko Oct 21, 2025
8c7c0d9
helium/ui/vertical-tabs/tab-strip: add missing tab_strip_region_view.h
wukko Oct 21, 2025
1d2f9ef
helium/ui/vertical-tabs: smoother open/close animations
wukko Oct 21, 2025
19e1815
helium/ui/vertical-tabs: initial fix for toolbar click events
wukko Oct 23, 2025
ceea26c
helium/ui/vertical-tabs/tab-search: refresh
wukko Oct 23, 2025
2cb22bc
helium/ui/vertical-tabs: new tab groups ui
wukko Oct 25, 2025
636ac7a
Merge remote-tracking branch 'upstream/main' into nhnn/vertical-tabs
thenhnn Nov 2, 2025
173e005
helium/ui/vertical-tabs/tab-groups: fix color indicator alignment
wukko Oct 25, 2025
76fdfd4
helium/ui/vertical-tabs/ui: fix multiple tab dragging
wukko Oct 25, 2025
b5955f6
helium/ui/vertical-tabs/tab-strip: disable horizontal scrollbar
wukko Oct 28, 2025
9c5b4be
chore: rebase on top of Chromium 142.0.7444.59
thenhnn Nov 2, 2025
79ec844
refresh: refresh patches
thenhnn Nov 2, 2025
54193af
fix: make it work
thenhnn Nov 3, 2025
81455be
fix: make traffic lights on macOS work again
thenhnn Nov 3, 2025
dc3d66c
fix: fix mac headers and fix contents width
thenhnn Nov 4, 2025
dd03d47
fix: wip toast repositioning
thenhnn Nov 8, 2025
6748c08
merge: changes from main
wukko Dec 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -4325,8 +4325,6 @@ static_library("ui") {
"views/tabs/browser_tab_strip_controller.h",
"views/tabs/color_picker_view.cc",
"views/tabs/color_picker_view.h",
- "views/tabs/compound_tab_container.cc",
- "views/tabs/compound_tab_container.h",
"views/tabs/dragging/drag_session_data.cc",
"views/tabs/dragging/drag_session_data.h",
"views/tabs/dragging/dragging_tabs_session.cc",
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -59,7 +59,6 @@
#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h"
-#include "chrome/browser/ui/views/tabs/compound_tab_container.h"
#include "chrome/browser/ui/views/tabs/dragging/tab_drag_controller.h"
#include "chrome/browser/ui/views/tabs/tab.h"
#include "chrome/browser/ui/views/tabs/tab_container_impl.h"
@@ -135,10 +134,6 @@ std::unique_ptr<TabContainer> MakeTabCon
TabStrip* tab_strip,
TabHoverCardController* hover_card_controller,
TabDragContext* drag_context) {
- if (base::FeatureList::IsEnabled(tabs::kSplitTabStrip)) {
- return std::make_unique<CompoundTabContainer>(
- *tab_strip, hover_card_controller, drag_context, *tab_strip, tab_strip);
- }
return std::make_unique<TabContainerImpl>(
*tab_strip, hover_card_controller, drag_context, *tab_strip, tab_strip);
}
56 changes: 56 additions & 0 deletions patches/helium/ui/vertical-tabs/feature-flag.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
--- a/chrome/browser/ui/tabs/features.cc
+++ b/chrome/browser/ui/tabs/features.cc
@@ -45,6 +45,10 @@ BASE_FEATURE(kVerticalTabs, base::FEATUR

BASE_FEATURE(kTabSelectionByPointer, base::FEATURE_DISABLED_BY_DEFAULT);

+BASE_FEATURE(kHeliumVerticalTabs,
+ "HeliumVerticalTabs",
+ base::FEATURE_DISABLED_BY_DEFAULT);
+
bool CanShowTabSearchPositionSetting() {
// Alternate tab search locations cannot be repositioned.
if (features::HasTabSearchToolbarButton()) {
@@ -67,4 +71,8 @@ bool IsVerticalTabsFeatureEnabled() {
return base::FeatureList::IsEnabled(kVerticalTabs);
}

+bool AreHeliumVerticalTabsEnabled() {
+ return base::FeatureList::IsEnabled(kHeliumVerticalTabs);
+}
+
} // namespace tabs
--- a/chrome/browser/ui/tabs/features.h
+++ b/chrome/browser/ui/tabs/features.h
@@ -38,6 +38,9 @@ bool CanShowTabSearchPositionSetting();
bool AreTabGroupShortcutsEnabled();
bool IsVerticalTabsFeatureEnabled();

+BASE_DECLARE_FEATURE(kHeliumVerticalTabs);
+extern bool AreHeliumVerticalTabsEnabled();
+
} // namespace tabs

#endif // CHROME_BROWSER_UI_TABS_FEATURES_H_
--- a/chrome/browser/helium_flag_choices.h
+++ b/chrome/browser/helium_flag_choices.h
@@ -31,6 +31,8 @@ namespace helium {
constexpr const char kAudioContextJitterCommandLine[] = "fingerprinting-audio-context-jitter";
constexpr const char kMiddleClickAutoscrollCommandLine[] = "middle-click-autoscroll";

+ constexpr const char kHeliumVerticalTabsCommandLine[] = "helium-vertical-tabs";
+
} // namespace helium

#endif /* CHROME_BROWSER_HELIUM_FLAG_CHOICES_H_ */
--- a/chrome/browser/helium_flag_entries.h
+++ b/chrome/browser/helium_flag_entries.h
@@ -28,4 +28,8 @@
"Middle Click Autoscroll",
"Enables autoscroll on middle click. Helium flag, Chromium feature.",
kOsDesktop, FEATURE_VALUE_TYPE(blink::features::kHeliumMiddleClickAutoscroll)},
+ {helium::kHeliumVerticalTabsCommandLine,
+ "Enable Helium Vertical Tabs",
+ "Enables experimental vertical tabs layout in Helium. Will be unstable and buggy, WIP. Helium flag.",
+ kOsDesktop, FEATURE_VALUE_TYPE(tabs::kHeliumVerticalTabs)},
#endif /* CHROME_BROWSER_HELIUM_FLAG_ENTRIES_H_ */
165 changes: 165 additions & 0 deletions patches/helium/ui/vertical-tabs/frame-layout.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
--- a/chrome/browser/ui/layout_constants.cc
+++ b/chrome/browser/ui/layout_constants.cc
@@ -21,6 +21,7 @@

int GetLayoutConstant(LayoutConstant constant) {
const bool touch_ui = ui::TouchUiController::Get()->touch_ui();
+ const bool vertical_tabs = tabs::AreHeliumVerticalTabsEnabled();
switch (constant) {
case TOP_BAR_VERTICAL_PADDING:
return 3;
@@ -94,13 +95,21 @@ int GetLayoutConstant(LayoutConstant con
return touch_ui ? 12 : 16;
case TAB_CLOSE_BUTTON_SIZE:
return touch_ui ? 24 : 16;
- case TAB_HEIGHT:
- return 31;
- case TAB_STRIP_HEIGHT:
- return GetLayoutConstant(TAB_HEIGHT) +
- GetLayoutConstant(TAB_STRIP_PADDING);
+ case TAB_HEIGHT: {
+ const int base_height = 28;
+ return !vertical_tabs ?
+ base_height + GetLayoutConstant(TOP_BAR_VERTICAL_PADDING) :
+ base_height;
+ }
+ case TAB_STRIP_HEIGHT: {
+ int padding = GetLayoutConstant(TOP_BAR_VERTICAL_PADDING);
+ if (vertical_tabs) {
+ padding = padding * 2;
+ }
+ return GetLayoutConstant(TAB_HEIGHT) + padding;
+ }
case TAB_STRIP_PADDING:
- return GetLayoutConstant(TOP_BAR_VERTICAL_PADDING);
+ return vertical_tabs ? 0 : GetLayoutConstant(TOP_BAR_VERTICAL_PADDING);
case TAB_SEPARATOR_HEIGHT:
return touch_ui ? 24 : 20;
case TAB_PRE_TITLE_PADDING:
@@ -186,6 +195,11 @@ gfx::Insets GetLayoutInsets(LayoutInset
case TOOLBAR_INTERIOR_MARGIN: {
const int vert = GetLayoutConstant(TOP_BAR_VERTICAL_PADDING);
const int horiz = vert * 2;
+
+ if (tabs::AreHeliumVerticalTabsEnabled()) {
+ return gfx::Insets::VH(vert, horiz + vert);
+ }
+
return touch_ui ? gfx::Insets() :
gfx::Insets::TLBR(0, horiz, vert, horiz);
}
--- a/chrome/browser/ui/views/frame/browser_root_view.cc
+++ b/chrome/browser/ui/views/frame/browser_root_view.cc
@@ -344,7 +344,7 @@ bool BrowserRootView::OnMouseWheel(const
// Scroll-event-changes-tab is incompatible with scrolling tabstrip, so
// disable it if the latter feature is enabled.
if (scroll_event_changes_tab_ &&
- !base::FeatureList::IsEnabled(tabs::kScrollableTabStrip)) {
+ !base::FeatureList::IsEnabled(tabs::kScrollableTabStrip) && !tabs::AreHeliumVerticalTabsEnabled()) {
// Switch to the left/right tab if the wheel-scroll happens over the
// tabstrip, or the empty space beside the tabstrip.
views::View* hit_view = GetEventHandlerForPoint(event.location());
--- a/chrome/browser/ui/views/frame/browser_view_layout.cc
+++ b/chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -548,10 +548,22 @@ void BrowserViewLayout::LayoutTabStripRe
if (web_app_frame_toolbar_) {
tab_strip_region_bounds.Inset(gfx::Insets::TLBR(
0, 0, 0, web_app_frame_toolbar_->GetPreferredSize().width()));
+ } else if (tabs::AreHeliumVerticalTabsEnabled()) {
+ int top_offset = tab_strip_region_bounds.height();
+ tab_strip_region_bounds = gfx::Rect(0, top_offset,
+ BrowserView::kVerticalTabStripWidth,
+ available_bounds.height() - top_offset);
}

if (tabs::IsVerticalTabsFeatureEnabled() && ShouldDisplayVerticalTabs()) {
SetViewVisibility(tab_strip_region_view_, false);
+ } else if (tabs::AreHeliumVerticalTabsEnabled()) {
+ SetViewVisibility(tab_strip_region_view_, true);
+ available_bounds.set_x(available_bounds.x() +
+ BrowserView::kVerticalTabStripWidth);
+ tab_strip_region_view_->SetBoundsRect(tab_strip_region_bounds);
+ top_container_->ReorderChildView(tab_strip_region_view_,
+ top_container_->children().size());
} else {
SetViewVisibility(tab_strip_region_view_, true);
tab_strip_region_view_->SetBoundsRect(tab_strip_region_bounds);
@@ -580,13 +592,13 @@ void BrowserViewLayout::LayoutToolbar(gf
bool toolbar_visible = delegate_->IsToolbarVisible();
SetViewVisibility(toolbar_, toolbar_visible);

- if (tabs::IsVerticalTabsFeatureEnabled() && ShouldDisplayVerticalTabs()) {
- gfx::Rect toolbar_bounds(
+ if ((tabs::IsVerticalTabsFeatureEnabled() && ShouldDisplayVerticalTabs())
+ || tabs::AreHeliumVerticalTabsEnabled()) {
+ gfx::Rect tab_strip_region_bounds(
delegate_->GetBoundsForToolbarInVerticalTabBrowserView());
- toolbar_bounds.set_x(available_bounds.x());
- toolbar_bounds.set_width(toolbar_bounds.width() -
- BrowserView::kVerticalTabStripWidth);
- toolbar_->SetBoundsRect(toolbar_bounds);
+ int height = toolbar_visible ? tab_strip_region_bounds.height() : 0;
+ toolbar_->SetBounds(tab_strip_region_bounds.x(), available_bounds.y(),
+ tab_strip_region_bounds.width(), height);
} else {
int height = toolbar_visible ? toolbar_->GetPreferredSize().height() : 0;
int width = available_bounds.width();
@@ -727,7 +739,7 @@ BrowserViewLayout::CalculateContentsCont
const gfx::Rect& available_bounds) const {
gfx::Rect contents_container_bounds = available_bounds;
int vertical_tab_offset = 0;
- if (tabs::IsVerticalTabsFeatureEnabled() && ShouldDisplayVerticalTabs()) {
+ if (delegate_->ShouldDrawTabStrip() && ((tabs::IsVerticalTabsFeatureEnabled() && ShouldDisplayVerticalTabs()) || tabs::AreHeliumVerticalTabsEnabled())) {
vertical_tab_offset = BrowserView::kVerticalTabStripWidth;
contents_container_bounds.set_width(available_bounds.width() -
vertical_tab_offset);
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -138,7 +138,7 @@ class BrowserView : public BrowserWindow

public:
// The width of the vertical tab strip.
- static constexpr int kVerticalTabStripWidth = 240;
+ static constexpr int kVerticalTabStripWidth = 210;

explicit BrowserView(Browser* browser);
BrowserView(const BrowserView&) = delete;
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -4868,6 +4868,15 @@ int BrowserView::NonClientHitTest(const
}
}

+ // In vertical tabs mode, check if the point is within the toolbar and
+ // allow the toolbar to handle the event instead of the system frame.
+ if (tabs::AreHeliumVerticalTabsEnabled() && toolbar_) {
+ gfx::Point test_point(point);
+ if (ConvertedHitTest(parent(), toolbar_, &test_point)) {
+ return HTCLIENT;
+ }
+ }
+
// Let the frame handle any events that fall within the bounds of the window
// controls overlay.
if (IsWindowControlsOverlayEnabled() && GetActiveWebContents()) {
--- a/chrome/browser/ui/views/frame/browser_native_widget_mac.mm
+++ b/chrome/browser/ui/views/frame/browser_native_widget_mac.mm
@@ -19,7 +19,9 @@
#import "chrome/browser/ui/cocoa/browser_window_command_handler.h"
#import "chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.h"
#import "chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h"
+#include "chrome/browser/ui/layout_constants.h"
#include "chrome/browser/ui/lens/lens_overlay_entry_point_controller.h"
+#include "chrome/browser/ui/tabs/features.h"
#include "chrome/browser/ui/views/frame/browser_frame_view.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/browser_widget.h"
@@ -156,7 +158,7 @@ void BrowserNativeWidgetMac::GetWindowFr
browser_view_->browser_widget()->GetFrameView()) {
*override_titlebar_height = true;
*titlebar_height =
- browser_view_->GetTabStripHeight() +
+ (tabs::AreHeliumVerticalTabsEnabled() ? GetLayoutConstant(TAB_STRIP_HEIGHT) : browser_view_->GetTabStripHeight()) +
browser_view_->browser_widget()->GetFrameView()->GetTopInset(true);
if (!browser_view_->ShouldDrawTabStrip()) {
*titlebar_height +=
Loading
Loading