How Vertical Tab Extensions Use the Firefox Sidebar API

This article provides a quick overview of the technical relationship between popular vertical tab extensions, such as Tree Style Tab and Sidebery, and the Firefox Web Browser's Sidebar API. It covers how these extensions allocate user interface space, synchronize with browser tabs in real-time, maintain hierarchical tree structures across sessions, and navigate the security limitations of the Firefox WebExtensions framework.

Declaring the Sidebar Space

To exist in the Firefox sidebar, extensions like Tree Style Tab and Sidebery must first declare their presence in their manifest.json configuration file. They achieve this using the sidebar_action manifest key.

This key defines the default title, icon, and, most importantly, the local HTML file (default_panel) that Firefox will render inside the sidebar container. Unlike content scripts that are injected into standard web pages, this HTML file runs in a privileged extension context. It acts as a persistent, independent webpage positioned next to the main browser viewport, styled entirely with the extension's own CSS.

Controlling the View with browser.sidebarAction

Once declared in the manifest, the extension controls the sidebar's behavior using the browser.sidebarAction JavaScript API. This API allows the extension to programmatically open, close, or toggle the sidebar panel—usually in response to a user clicking a toolbar button or pressing a keyboard shortcut like F1.

Because a user might have multiple Firefox windows open at once, the sidebarAction API scopes its operations by windowId. This allows Sidebery and Tree Style Tab to render a unique sidebar instance for every open window, ensuring that the vertical tab bar only displays the tabs relevant to the specific window the user is currently viewing.

Real-Time Synchronization via browser.tabs

The Sidebar API itself is merely a blank container; it does not inherently know anything about browser tabs. To function as a tab manager, vertical tab extensions rely heavily on the browser.tabs API.

When the sidebar HTML document loads, its JavaScript executes browser.tabs.query({currentWindow: true}) to fetch an array of all open tabs in that window. The extension then builds a Document Object Model (DOM) representation of these tabs inside the sidebar.

To keep the sidebar synchronized with the browser, the extension attaches event listeners to the browser.tabs API:

  • onCreated: Fires when a new tab is opened, prompting the extension to insert a new tab element into the sidebar DOM.
  • onRemoved: Fires when a tab is closed, telling the extension to delete the corresponding element.
  • onUpdated: Fires when a tab's URL, title, or favicon changes, allowing the sidebar to update loading spinners and text.
  • onActivated: Fires when the user switches tabs, allowing the extension to highlight the newly active tab in the vertical list.

Conversely, when a user clicks, drags, or closes a tab inside the extension's sidebar, the extension captures that click event and sends a command back to Firefox (such as browser.tabs.remove() or browser.tabs.move()) to execute the action in the actual browser.

Creating and Saving the "Tree" Structure

Firefox’s native tab system is completely flat, meaning the browser does not natively understand parent-child tab relationships. Tree Style Tab and Sidebery manufacture this hierarchy by combining the openerTabId property with the browser.sessions API.

When you middle-click a link on a webpage to open a new tab, Firefox records the ID of the source tab in the new tab's openerTabId property. The vertical tab extension reads this property and visually indents the new tab underneath the source tab in the sidebar's HTML.

However, if the user restarts Firefox, the openerTabId data can be lost or insufficient for complex trees. To solve this, extensions use the browser.sessions.setTabValue() API. This allows the extension to attach custom JSON metadata—such as tree depth, custom group colors, collapsed states, and parent IDs—directly to the native Firefox tab object. When Firefox restarts and restores the session, the extension calls getTabValue() on every tab to reconstruct the exact visual tree structure.

API Limitations and the Native Tab Bar

While the interaction between these extensions and the Firefox API is robust, it is restricted by WebExtensions security boundaries. The Sidebar API only grants the extension control over the rectangular box of the sidebar itself; it does not allow the extension to modify the rest of the Firefox user interface.

Because there is no API available to hide the native horizontal tab strip at the top of the browser, users of Tree Style Tab and Sidebery end up with two visible tab bars by default. To bypass this API limitation, users must manually create a userChrome.css file in their Firefox profile directory to hide the native horizontal tabs using custom CSS rules.