Repository navigation
How the Single Tab Title Works
This chapter explains how a tab strip with one tab turns into a centered title in single tab mode. The user side is in Single Tab Title; the rest of the strip (drag, pin, wrap) is in How tabs are arranged.
With one file open, the strip is a single tab on the left and empty space to the right. It looks unfinished, and the tab frame adds nothing when there is no other tab to tell it apart from. The user asked to move the lone tab to the center and show it like a name, and then to keep it to single tab mode (Settings > Editor > Tab limit > Single tab): there one file at a time is the point, while with other limits a lone tab is just a moment before the next file opens.
The decision is one pure function in src/lib/stores/tabs.ts:
showsTabAsTitle(enabled, tabLimit, tabCount, diffOpen)It is true when the setting is on, tabLimit is SINGLE_TAB (from tabLimit.ts) and the strip holds exactly one item. The Diff tab of the Changes view counts as an item, because it sits in the same strip as the others.
flowchart TD
Start["EditorTabs.svelte renders a group"] --> Setting{"settings.singleTabTitle?"}
Setting -- no --> Tabs["normal tabs"]
Setting -- yes --> Mode{"settings.tabLimit == SINGLE_TAB?"}
Mode -- no --> Tabs
Mode -- yes --> Count["items = tabs.length + (Diff tab shown ? 1 : 0)"]
Count --> One{"items == 1?"}
One -- yes --> Title["strip gets the single class: centered title"]
One -- no --> Tabs
EditorTabs.svelte derives single from that function for its own group and gives the library's TabStrip the single layout. Only the Diff tab counts in the primary group, since only that group shows it.
Nothing else in the markup changes. The title is the same .tab element with the same buttons and handlers, so the right-click menu, middle click, double-click to keep a preview, the dirty dot and the pin button all keep working with no extra code. The CSS does the rest:
-
justify-content: centeron the strip puts the tab in the middle. - The tab loses its right border, its background and the accent line (
::before). - The tab can shrink (
flex: 0 1 auto,min-width: 0), so a long name ends in an ellipsis instead of overflowing a centered strip, which would cut off its start with no way to scroll to it. - The tab gets a left padding equal to the close button's width, so the name sits in the true middle, not 20 px to the left.
- The close button always shows, even when the tab is not the active one (for example while another view is open), so the lone file can be closed without hunting for it. A dirty tab still shows its dot until hover, like any tab.
- Under Rounded panels, the pill background and outline are cleared too.
Dragging needs at least two tabs (startDrag returns null otherwise), so the title can never be dragged.
| File | What it does |
|---|---|
src/lib/stores/tabs.ts |
showsTabAsTitle |
src/lib/views/EditorTabs.svelte, ui/web/src/lib/components/EditorTab.svelte
|
the single layout and its styles |
src/lib/stores/settingsData.ts |
the singleTabTitle preference (on by default) |
src/lib/stores/settings.svelte.ts |
the reactive singleTabTitle field and saving it |
src/lib/views/settings/EditorFeatureSettings.svelte |
the Single tab title switch, shown under Tab limit only while Single tab is chosen |
A class, not a second component. Rendering a separate title element would mean copying the tab's buttons, menu and handlers, and keeping both in sync. Styling the same element keeps every tab action working and costs nothing in memory.
Only in single tab mode. With no limit or a number limit, the strip grows and shrinks as files open, and a title that turns into a tab and back each time would jump around. In single tab mode the strip almost always holds one file, so the title is stable.
On by default, under Tab limit. The switch is a sub-row of Tab limit that shows only while Single tab is chosen, since it does nothing otherwise. Anyone who prefers a plain tab in single tab mode can turn it off.
The Diff tab counts. It shares the strip with the file tabs. Not counting it would show a title next to a Diff tab, which is two items again.
Per group. In a split editor each strip decides alone, so a group with one file still looks tidy next to a busy one.
-
src/lib/stores/tabs.test.ts:showsTabAsTitle(one tab, the setting off, other tab limits, the Diff tab counted, empty and full strips). -
src/lib/stores/settingsData.test.ts: thesingleTabTitledefault and validation.
The centered look, the always visible close button and the Rounded panels styles need a visual check in the app.
- Update this page and Single Tab Title when the rule or the look changes.
- A new kind of item in the strip must be counted in the call to
showsTabAsTitle. - A new tab style (for example in Rounded panels) must be cleared for the
singlestrip. - See Docs and Screenshots.
These pages are generated from docs/wiki. To correct something, open a pull request against the source file; edits made here are overwritten.
Using Nibtree
- Getting Started
- Welcome Screen
- Workspaces
- Files Panel
- File Operations
- File Icons
- Rounded Panels
- Editor and Tabs
- Pin Reorder and Wrap Tabs
- Single Tab Title
- Split Editor
- New File and Unsaved Changes
- Unload Hidden Tabs
- Editing Code
- Code Appearance
- Markdown Editor
- Image and PDF Preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and Replace
- Changes and Commits
- Sign In Prompts
- Commit Box Layout
- Repository Actions
- Commit Options
- Ignoring Files
- Diffs
- Inline Diffs
- Staging View
- Revert a Change
- Resolving Conflicts
- Merge Tool
- Blame
- History and Log
- Merge Commits
- Branches and Tags
- Branches Popup
- Remotes
- Stashes
- Shelf
- Git Menu
- Git Dialogs
- Interactive Rebase
- Worktrees
- AI Agents
- AI Tasks
- AI Usage
- Keep Computer Awake
- Submodules
- Git LFS
- GitHub
- Git Console
- Terminal
- Terminal Features
- Scripts
- Navigation
- Menus
- Settings
- Settings Search
- Color Themes
- Settings Terminal and Automation
- Settings Files
- Updates
- Status Bar and Help
- Notifications
- Memory Use
- Clear Cache
- MCP and CLI
- Git Mergetool
- Keyboard Shortcuts
- Keyboard Shortcuts Editor
- Troubleshooting
- Troubleshooting Git
Developers
- Developer Guide
- Architecture
- Project Layout
- Backend
- How Folder Watching Works
- Folder Watching Bugs We Fixed
- How Workspace Files Work
- How the Preview Scheme Works
- Backend Services
- How Terminal Features Work
- Terminal Bugs We Fixed
- Frontend
- How the Rich Markdown Editor Works
- Rich Markdown Bugs We Fixed
- Git Menu Links
- Menu Keys and Routing
- Frontend Modules
- Blame Bugs We Fixed
- Project Color And Title Bar
- One Diff View
- Diff Bugs We Fixed
- Merge Tool Layouts
- Merge Tool Bugs We Fixed
- Color Theme Bugs We Fixed
- How the Connected Diff Works
- Rounded Panels Bugs We Fixed
- Update Bugs We Fixed
- Status Bar Bugs We Fixed
- MCP and CLI Bugs We Fixed
- Repository Actions Bugs We Fixed
- How the Changes Tab Works
- CodeMirror Patterns
- How the Cursor Works
- How Editor Features Work
- How the Path Bar Works
- Commands and Events
- Settings Reference
- Commands Workspace and Changes
- Commands Branches and Remotes
- Commands History and Extras
- Commands App and Tools
- Testing
- Test Suites
- Debugging
- Debugging with MCP
- Measuring Setting Memory
- How Terminal Memory Is Measured
- How Markdown Diagrams Work
- Releases and CI
- Publishing the Wiki
- Versioning and Changelog
- Browser Version Packages
- Browser Release Checks
- Docker Image
- Platforms and Signing
- Windows Support
- Windows Bugs We Fixed
- Windows MCP and CLI
- Docs and Screenshots
- UI Library
- UI Library MCP
- UI Library Bugs
- UI Library Migration
- Contributing
How features work
- Welcome screen
- Workspaces and folders
- Files panel
- File operations
- File icons
- Editor and tabs
- Pin, reorder and wrap tabs
- Single tab title
- Split editor
- New File and unsaved changes
- Unload hidden tabs
- Editing code
- Code appearance
- Markdown editor
- Image and PDF preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and replace
- Changes and commits
- Sign-in prompts
- Commit box layout
- Repository actions
- Commit options
- Ignoring files
- Diffs
- Inline diffs
- Staging view
- Revert a change
- Resolving conflicts
- Merge tool
- Blame
- History and log
- Merge commits
- Commit tabs
- Branches and tags
- Branches popup
- Remotes
- Stashes
- Shelf
- Git menu
- Git dialogs
- Interactive rebase
- Worktrees
- AI agents
- AI usage
- Keep computer awake
- AI tasks
- Submodules
- Git LFS
- GitHub account
- Git Console
- Back and Forward
- Integrated terminal
- Scripts tool window
- Menu bar
- Settings
- Search in Settings
- Color themes
- Rounded panels
- Updates and release channels
- Status bar and help links
- Notifications
- Memory readout and memory log
- Clear Cache
- MCP server and command line tool
- git mergetool mode