Skip to content

Add option to show pinned tabs in a separate row#46573

Merged
mattermill merged 6 commits intozed-industries:mainfrom
yaroslavrick:feature/two-row-pinned-tabs
Jan 13, 2026
Merged

Add option to show pinned tabs in a separate row#46573
mattermill merged 6 commits intozed-industries:mainfrom
yaroslavrick:feature/two-row-pinned-tabs

Conversation

@yaroslavrick
Copy link
Contributor

@yaroslavrick yaroslavrick commented Jan 11, 2026

Problem:

When working with many pinned tabs, they consume significant horizontal space in the tab bar, leaving less room for unpinned (active working) tabs, especially on small screens. This creates a poor user experience as users must constantly scroll to find their working tabs, or the tabs become too narrow to read file names.

8_tabs

Solution:

Added a new opt-in setting tab_bar.show_pinned_tabs_in_separate_row that displays pinned and unpinned tabs in two separate rows:

  • Top row: Pinned tabs with navigation buttons and tab bar controls

  • Bottom row: Unpinned (working) tabs with full horizontal space

  • when pinned and not pinned tabs we show 2 rows:

2_rows

This is a well-established UX pattern used in many popular IDEs including JetBrains products (IntelliJ IDEA, WebStorm, PyCharm, RubyMine), Visual Studio, and Eclipse.

The two-row layout only appears when both pinned AND unpinned tabs exist. If only one type is present, a single row is displayed:

  • when only not pinned tabs we show one row:
when only not pinned
  • when only pinned tabs we show one row:
when only pinned tabs

Important - Default Behavior Preserved:

  • The setting defaults to false - existing users will see no change whatsoever
  • Original tab bar logic is preserved in a dedicated render_single_row_tab_bar method, while the new two-row layout lives in render_two_row_tab_bar. Both methods share common components (configure_tab_bar_start, configure_tab_bar_end, render_unpinned_tabs_container, render_tab_bar_drop_target) ensuring DRY code and consistent behavior.
  • Purely opt-in - users must explicitly enable this feature via Settings UI or settings.json
  • No impact on default UX - Zed's default tab bar appearance and behavior remains identical

This implementation ensures zero risk to the existing user experience while providing an optional enhancement for users who prefer separated tab rows.

Configuration

Via Settings UI:

  • Open Settings (Cmd+,) → Editor section → "Pinned Tabs Layout" toggle

settings_ui

Via settings.json:

{
  "tab_bar": {
    "show_pinned_tabs_in_separate_row": true
  }
}
manual_settings

Video of implemented feature:

720.mov

Tested:

  • Verify default behavior unchanged (single row with pinned + unpinned tabs inline)
  • Enable setting → verify two rows appear when both pinned and unpinned tabs exist
  • Enable setting → verify single row when only pinned tabs exist
  • Enable setting → verify single row when only unpinned tabs exist
  • Verify drag & drop works in both layouts
  • Verify navigation buttons and tab bar buttons render correctly
  • Verify setting toggle works in Settings UI
  • Verify setting works via settings.json

Tested on: MacBook Pro M4, macOS 26.2

Release Notes:

  • Added tab_bar.show_pinned_tabs_in_separate_row setting to display pinned and unpinned tabs in separate rows, giving unpinned tabs full horizontal space

@cla-bot
Copy link

cla-bot bot commented Jan 11, 2026

We require contributors to sign our Contributor License Agreement, and we don't have @yaroslavrick on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@yaroslavrick
Copy link
Contributor Author

@cla-bot check

@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Jan 11, 2026
@cla-bot
Copy link

cla-bot bot commented Jan 11, 2026

The cla-bot has been summoned, and re-checked this pull request!

@yaroslavrick yaroslavrick changed the title Implement separate pinned tabs row feature Separate pinned tabs row feature Jan 11, 2026
@yaroslavrick yaroslavrick changed the title Separate pinned tabs row feature Add option to show pinned tabs in a separate row Jan 11, 2026
@yaroslavrick
Copy link
Contributor Author

Correct me if I'm wrong, but it looks like the failed test in CI is flaky:

image

It passes locally on my machine. I don't have permission to re-run the CI. @mattermill Could you please re-run it?

@mattermill mattermill merged commit 72f6d39 into zed-industries:main Jan 13, 2026
36 of 39 checks passed
@williamdes
Copy link
Contributor

Thank you so much, I will enable this as soon as tomorrow!
Since you have experience with the tab bars, would you make them wrap tabs ?

See issue #5005

@KieranP
Copy link

KieranP commented Jan 15, 2026

This may have broken tab reordering when not enabled - please see #46864

@yaroslavrick
Copy link
Contributor Author

This may have broken tab reordering when not enabled - please see #46864

I will take a look at this

@yaroslavrick
Copy link
Contributor Author

yaroslavrick commented Jan 15, 2026

This may have broken tab reordering when not enabled - please see #46864

Seems that I've found the roots of issue: here is this line: 10b2072#diff-f3e6f80bf80e98b614b1fba64a700fc347b10286412e005f363e52279a550244R2768

crates/workspace/src/pane.rs:2768

cc @mattermill

cx.listener(move |this, dragged_tab: &DraggedTab, window, cx| {
this.drag_split_direction = None;
this.handle_tab_drop(dragged_tab, ix, window, cx)
this.handle_tab_drop(dragged_tab, this.items.len(), window, cx)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Seems that I've found the roots of issue: here is this line: 10b2072#diff-f3e6f80bf80e98b614b1fba64a700fc347b10286412e005f363e52279a550244R2768

crates/workspace/src/pane.rs:2768

cc @mattermill

Copy link
Contributor Author

Choose a reason for hiding this comment

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

PR of fix: #46872

@yaroslavrick
Copy link
Contributor Author

This may have broken tab reordering when not enabled - please see #46864

PR of fix: #46872

smitbarmase added a commit that referenced this pull request Jan 15, 2026
Closes [#46864](#46864)
Initial PR: #46573

## Summary

Fix a regression where dragging a tab onto another tab would place it at
the end of the tab bar instead of at the target position.

The issue was in the `on_drop` handler: it used `this.items.len()`
(evaluated at drop time) instead of the captured `ix` index (the
position of the tab being dropped onto).

Release Notes:

- Fixed tab reordering not working correctly when dragging tabs

## Video after fix:

- when 'show_pinned_tabs_in_separate_row' is false:


https://github.com/user-attachments/assets/1ede0ce5-1161-4209-83f4-33a07572782a

- when 'show_pinned_tabs_in_separate_row' is true:


https://github.com/user-attachments/assets/d56c0e59-8372-41d4-973b-32a4895ca729

---------

Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
github-actions bot pushed a commit that referenced this pull request Jan 15, 2026
Closes [#46864](#46864)
Initial PR: #46573

## Summary

Fix a regression where dragging a tab onto another tab would place it at
the end of the tab bar instead of at the target position.

The issue was in the `on_drop` handler: it used `this.items.len()`
(evaluated at drop time) instead of the captured `ix` index (the
position of the tab being dropped onto).

Release Notes:

- Fixed tab reordering not working correctly when dragging tabs

## Video after fix:

- when 'show_pinned_tabs_in_separate_row' is false:


https://github.com/user-attachments/assets/1ede0ce5-1161-4209-83f4-33a07572782a

- when 'show_pinned_tabs_in_separate_row' is true:


https://github.com/user-attachments/assets/d56c0e59-8372-41d4-973b-32a4895ca729

---------

Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
zed-zippy bot added a commit that referenced this pull request Jan 15, 2026
…view) (#46878)

Cherry-pick of #46872 to preview

----
Closes [#46864](#46864)
Initial PR: #46573

## Summary

Fix a regression where dragging a tab onto another tab would place it at
the end of the tab bar instead of at the target position.

The issue was in the `on_drop` handler: it used `this.items.len()`
(evaluated at drop time) instead of the captured `ix` index (the
position of the tab being dropped onto).

Release Notes:

- Fixed tab reordering not working correctly when dragging tabs

## Video after fix:

- when 'show_pinned_tabs_in_separate_row' is false:



https://github.com/user-attachments/assets/1ede0ce5-1161-4209-83f4-33a07572782a

- when 'show_pinned_tabs_in_separate_row' is true:



https://github.com/user-attachments/assets/d56c0e59-8372-41d4-973b-32a4895ca729

---------

Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>

Co-authored-by: Yaroslav Yenkala <yaroslavrick@gmail.com>
Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
@JosephTLyons
Copy link
Collaborator

Hey @yaroslavrick, caught this bug: #46926

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants