Skip to content

API for other addons

YUKI "Piro" Hiroshi edited this page Aug 21, 2024 · 237 revisions

This describes about Tree Style Tab 2.x API for other WebExtensions-based addons. See also old documentation about Legacy TST 0.19.x (Japanese translation)

(generated by Table of Contents Generator for GitHub Wiki)

And there are more APIs for specific purposes.

Abstract

Important Note: this document assumes that you have experienced to develop one ore mroe Firefox extensions. If you've never done it, I recommend you to see the basic document for extensions authors.

To communicate with TST, your addon can send messages to TST via browser.runtime.sendMessage(). You need to specify TST's internal ID [email protected] as the first argument of the method.

Any API message for TST is an object with a string property named type, which indicates the type of the message. For example:

const TST_ID = '[email protected]';
let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'register-self',
  name: 'My Addon',
  icons: browser.runtime.getManifest().icons,
  listeningTypes: ['tab-mousedown', 'tab-mouseup'],
  permissions: ['tabs']
});

You'll receive returned value from TST APIs as a promise.

On TST 4.0 and later, you can send multiple messages at once to reduce cross-addon messagings, like as:

const TST_ID = '[email protected]';
let responses = await browser.runtime.sendMessage(TST_ID, {
  messages: [
    { type: 'get-tree',
      tabId: 1 },
    { type:  'set-extra-contents',
      tabId: 2,
      place: 'tab-indent',
      contents: ... },
    { type:  'set-extra-contents',
      tabId: 3,
      place: 'tab-behind',
      contents: ... },
  ],
});

You'll get an array of responses for sent messages.

On TST 3.5.4 and later, browser.runtime.connect() is also available to send messages if you don't need responses. For example:

const TSTConnection = browser.runtime.connect(TST_ID, { name: `connection from ${browser.runtime.id}` });
TSTConnection.postMessage({
  type: 'scroll-lock'
});

This way will help you to send very large number of messages with better performance. And of couse you can send multiple messages at once with this method, like as the previous example, on TST 4.0 and later.

Here is a boilerplate to implement your custom helper addon for TST.

This page explains most APIs but some specific APIs are explained in sub pages:

Detecting version of TST itself

TST 4.0 and later supports a message type get-version. Example usage:

let TSTVersion = await browser.runtime.sendMessage(TST_ID, { type: 'get-version' });
// TSTVersion = "4.0.1" or something string if responded, otherwise `null` will be got.

You'll get null response if the version of TST is older than 4.0, so you can deactivate some features if it depends on lately versions of TST but not updated yet on the runtime environment.

Register and unregister your addon to TST

Register and unregister

Basics

You need to register your addon to TST, to receive notification messages from TST. Send a message with the type register-self to TST, like:

async function registerToTST() {
  try {
  let result = await browser.runtime.sendMessage(TST_ID, {
    type: 'register-self',
    // The name of your addon (string, optional)
    name: browser.i18n.getMessage('extensionName'),
    // Icons (used for extra context menu items, works on TST 2.4.18 and later)
    icons: browser.runtime.getManifest().icons, // { '16': '/path/to/icon.png', 24: '...', ... }
    // The list of listening message types (array of string)
    listeningTypes: ['tab-mousedown', 'tab-mouseup'],
    // Accept bulk messages from TST (works on TST 4.0 and later)
    allowBulkMessaging: true,
    // Receive notified messages with light tree (works on TST 4.0 and later)
    lightTree: true,
    // Extra style rules applied in the sidebar (string, optional)
    style: `
      .tab.unread {
        color: red;
      }
    `,
    // Extra permissions to receive tab information via TST's API (works on TST 3.0.12 and later)
    permissions: ['tabs']
  });
  }
  catch(e) {
    // TST is not available
  }
}
registerToTST();

On TST 3.0.12 and later, the returned promise will be filled with an object with following properties, when TST successfully process the message:

On TST 3.0.11 and older, the promise is filled with just a boolean value true.

Auto re-registering on the startup of TST

When you addon is loaded and initialized before TST is initialized, no one responds to the message and you'll fail to register your addon. Because TST cannot broadcast any message to unknown addons, your addon won't receive any message from TST until it is successfully registered. So the user need to reload your addon manually if he install TST after your addon.

TST caches IDs of known registered addons and sends a message ready to them when TST is successfully initialized. For secondary and after startup cases, you should listen the message to re-register your addon safely, like:

function onMessageExternal(message, sender) {
  switch (sender.id) {
    case TST_ID:
      switch (message.type) {
        ...
        case 'ready':
        case 'permissions-changed':
          registerToTST(); // passive registration for secondary (or after) startup
          break;
        ...
      }
      break;
  }
}
browser.runtime.onMessageExternal.addListener(onMessageExternal);
registerToTST(); // aggressive registration on initial installation

After your addon is successfully registered, it will receive messages from TST via the event listener registered to browser.runtime.onMessageExternal. Note that you should keep listening the ready message from TST even if you successfully registered your addon, because you need to re-register your addon again when TST is reloaded while your addon is working.

Listening of notification messages

Note for Tree Style Tab 2.4.17 and later: You should list message types only your addon really requires, via the listeningTypes parameter. Otherwise, TST may change some behaviors of itself to wait responses from external addons. For backward compatibility, all known type messages on TST 2.4.16 (ready, shutdown, tab-clicked, tab-mousedown, tab-mouseup, tabbar-clicked, tabbar-mousedown, and tabbar-mouseup) will be delivered to your addon if you omit this parameter.

On TST 4.0 and later, you can specify an option lightTree: true to minimize messaging cost, like:

async function registerToTST() {
  try {
  let result = await browser.runtime.sendMessage(TST_ID, {
    type: 'register-self',
    ...
    listeningTypes: ['tabs-rendered'],
    lightTree: true,
    allowBulkMessaging: true, // Recommended to combine this option. See the next section also.
    ...
  });
  }
  catch(e) {
    // TST is not available
  }
}
registerToTST();

tab, tabs and other tab-like properties in notification messages delivered to your addon will become light tree when you specify this option. Huge number tabs (ex. 3000 or more) with full tree format may eat too much RAM while messagings and it may trigger GC too frequently. Light tree format expects reducing such performance issues.

Bulk messages from TST

For better performance, TST 4.0 and later may send multiple messages with some one-way notification types in bulk, if you registered your addon with the flag allowBulkMessaging: true. You'll receive a bulk messages as an object containing a property messages, and messages will be an array of regular notification messages. Here is an example to handle bulk messages:

async function registerToTST() {
  try {
  let result = await browser.runtime.sendMessage(TST_ID, {
    type: 'register-self',
    name: browser.i18n.getMessage('extensionName'),
    icons: browser.runtime.getManifest().icons,
    ...
    allowBulkMessaging: true, // IMPORTANT!
    ...
  });
  }
  catch(e) {
  }
}
registerToTST();

function onMessageExternal(message, sender) {
  switch (sender.id) {
    case TST_ID:
      if (message && message.messages) { // bulk message
        for (const oneMessage of message.messages) {
          onMessageExternal(oneMessage, sender);
        }
      }
      switch (message.type) {
        ...
      }
      break;
  }
}
browser.runtime.onMessageExternal.addListener(onMessageExternal);

Unregister from TST

You can unregister your addon from TST, to stop listening of notification messages. This will also remove all of following:

For unregisteration you need to send a unregister-self message from your addon:

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'unregister-self'
});

But actually you may not send such a message effectively, because beforeunload, unload and any other DOM event, or runtime.connect() way is not available to detect unloading of your addon. Therefore TST provides another way for unregisteration that detects when your extension is no longer available: a wait-for-shutdown type notification, on Tree Style Tab 3.1.2 and later.

This method is similar to how the wait-for-shutdown message that can be sent to TST works. Your extension needs to add the value wait-for-shutdown to listeningTypes of the 'register-self' message, and respond to the notification with a maybe never-resolved promise:

async function registerToTST() {
  try {
    let result = await browser.runtime.sendMessage(TST_ID, {
      type: 'register-self',
      name: browser.i18n.getMessage('extensionName'),
      listeningTypes: ['wait-for-shutdown'] // IMPORTANT!
    });
  }
  catch(e) {
    // TST is not available
  }
}

function onMessageExternal(message, sender) {
  switch (sender.id) {
    case TST_ID:
      ...
      switch (message.type) {
        ...
        case 'wait-for-shutdown': // IMPORTANT!
          return new Promise(() => { // Yes, this may not be resolved never.
            window.addEventListener('beforeunload', () => resolve(true)); // IMPORTANT!
          });
        ...
      }
      break;
  }
}
browser.runtime.onMessageExternal.addListener(onMessageExternal);

registerToTST();

For more details: the returned promise can be resolved or rejected manually if you needed.

  • If the promise is resolved with a true value or rejected with an error, then TST will unregister your extension automatically.
  • If the promise is resolved with a false value, then TST will not unregister your extension, so this way will effective for reloading or other cases.
  • The promise is rejected by Firefox itself automatically, when your addon is unloaded. (The example above aspects this case.)
  • A completely blank promise like new Promise(() => {}) won't work as you expected due to something "timeout" mechanism of FIrefox itself. If the returned promise doesn't do anything then there seems to be a timeout by Firefox, so it only works if tracked your extension is disabled within about 10 seconds after this promise is used as a response to a message. After that it will not throw an error for the waiting extension. Thus you should put something code to call the resolver function, even if the code may not be performed.

Here is a complex case example:

const promisedShutdown = new Promise((resolve, reject) => {
  // If we use the following then the returned promise will be rejected when
  // this extension is disabled even for longer times:
  window.addEventListener('beforeunload', () => resolve(true));
});

function onMessageExternal(message, sender) {
  switch (sender.id) {
    case TST_ID:
      ...
      switch (message.type) {
        ...
        case 'wait-for-shutdown':
          return promisedShutdown;
        ...
      }
      break;
  }
}
browser.runtime.onMessageExternal.addListener(onMessageExternal);

Please note that any wait-for-shutdown notification won't be sent on TST 3.1.1 and older.

Information in private windows

On TST 3.0.12 and later, tree item information and notification messages in private windows won't be provided if any of following cases:

  • TST itself is not granted to be activated on private windows.
  • Notifying of messages from private windows is not allowed for the addon, on TST's options.

A permissions-changed notification message will be delivered after the user grants (or deprives) accessing to information in private windows for your addon.

Extra permissions

Some TST APIs return or notify information of related tree items. Due to security reasons, they are not same to tabs.Tab on TST 3.0.12 and later, so you may need to use tabs.get() or tabs.query() parallelly to get full tab information on demand.

However, sometimes you may want to get event information and full tab information related to the event together, for example mouse events on tabs. For such special cases, TST provides its own permission system. You can add an optional parameter named permissions for the register-self type message. It should be an array of strings indicating requesting permissions. Possible values are:

  • activeTab: exposes title, url, and favIconUrl of the tab corresponding to the tree item, only for the active tab or the context tab for the fake context menu.
  • tabs: exposes title, url, and favIconUrl for all tabs corresponding to tree items.
  • cookies: exposes cookieStoreId for all tabs corresponding to tree items.

A permissions-changed notification message will be delivered after the user grants (or deprives) requested permissions for your addon. The user may not allow these permissions for your addon, so please remind that you should make your addon compatible for environments without permissions.

Uninit special features for TST when TST is going to be disabled

By limitations of WebExtensions APIs, TST cannot send something messages like "shutdown" to listeners when it is going to be disabled (and uninstalled). If your addon provides something special feature for TST, it won't work after TST is disabled dynamically. Thus you'll need something way to know that TST is still alive or not.

There are two APIs available for such a case:

  • wait-for-shutdown type message
  • ping type message

wait-for-shutdown type message

This is available on TST 2.7.17 or later.

If you send a message with the type wait-for-shutdown, TST simply returns a promised value it will be resolved after TST is disabled. However, please note that the promise is never been resolved. The promise will be rejected when TST becomes disabled or uninstalled. So you can do uninitialize your addon when the promise is rejected. For example:

browser.runtime.sendMessage(TST_ID, { type: 'wait-for-shutdown' })
  .finally(uninitFeaturesForTST);

More rich example:

async function waitForTSTShutdown() {
  try {
    // This message should always throw an error:
    await browser.runtime.sendMessage(TST_ID, { type: 'wait-for-shutdown' });

    // Will happen if message is not supported (TST 2.7.16 and earlier):
    return false;
  } catch (error) {
    // Extension was disabled before message was sent:
    if (error.message.startsWith("Could not establish connection. Receiving end does not exist."))
      return true;
    // Extension was disabled while we waited:
    if (error.message.startsWith("Message manager disconnected"))
      return true;

    // Probably an internal Tree Style Tab error:
    throw error;
  }
}
waitForTSTShutdown().then(uninitFeaturesForTST);

You'll see the reason why the API has such an odd style at the issue 2128.

ping type message

This is available on TST 2.0.3 or later.

If you send a message with the type ping, TST simply returns true as the result. On the other hand, if TST is not available, browser.runtime.sendMessage() will report an error. By these difference you can know TST's living status. For example:

function checkTSTAvailability() {
  try {
    await browser.runtime.sendMessage(TST_ID, {
      type: 'ping'
    });
  }
  catch(e) {
    clearInterval(checkTSTAvailability.timer);
    uninitFeaturesForTST();
  }
}
checkTSTAvailability.timer = setInterval(checkTSTAvailability, 10000);

Manipulate tree of tabs

Basics to specify tabs

Most of TST's APIs accept tabs.Tab.id or some alias names to specify target tabs like active, next-of-10, or more. Available aliases are:

  • current / active: the active tab in the last focused window.
  • parent: the parent tab of the active tab. (available at TST 3.8.5 and later)
    • parent-of-<Integer:id>: the parent tab of the specified tab. (available at TST 3.8.5 and later)
  • root: the root level parent tab of the active tab. (available at TST 3.8.5 and later)
    • root-of-<Integer:id>: the root level parent tab of the specified tab. (available at TST 3.8.5 and later)
  • next: the next tab of the active tab.
    • next-of-<Integer:id>: the next tab of the specified tab.
    • nextCyclic / nextCyclic-of-<Integer:id>: same to the next but the first tab is returned when there is no next tab.
  • nextVisible: the next visible (not collapsed) tab of the active tab.
    • nextVisible-of-<Integer:id>: the next visible (not collapsed) tab of the specified tab.
    • nextVisibleCyclic / nextVisibleCyclic-of-<Integer:id>: same to the nextVisible but the first visible tab is returned when there is no next visible tab.
  • nextSibling: the next sibling tab of the active tab.
    • nextSibling-of-<Integer:id>: the next sibling tab of the specified tab.
    • nextSiblingCyclic / nextSiblingCyclic-of-Integer:id: same to the nextSibling` but the first sibling is returned when there is no next sibling.
  • previous / prev: the previous tab of the active tab.
    • previous-of-<Integer:id> / prev-of-<Integer:id>: the previous tab of the specified tab.
    • previousCyclic / prevCyclic / previousCyclic-of-<Integer:id> / prevCyclic-of-<Integer:id>: same to the prev but the last tab is returned when there is no previous tab.
  • previousVisible / prevVisible: the previous visible (not collapsed) tab of the active tab.
    • previousVisible-of-<Integer:id> / prevVisible-of-<Integer:id>: the previous visible (not collapsed) tab of the specified tab.
    • previousVisibleCyclic / prevVisibleCyclic / previousVisibleCyclic-of-<Integer:id> / prevVisibleCyclic-of-<Integer:id>: same to the previousVisible but the last visible tab is returned when there is no previous visible tab.
  • previousSibling / prevSibling: the previous sibling tab of the active tab.
    • previousSibling-of-<Integer:id> / prevSibling-of-<Integer:id>: the previous sibling tab of the specified tab.
    • previousSiblingCyclic / prevSiblingCyclic / previousSiblingCyclic-of-<Integer:id> / prevSiblingCyclic-of-<Integer:id>: same to the previousSibling but the last sibling is returned when there is no previous sibling.
  • lastDescendant (TST 3.7.0-): the last descendant (the last child recursively found) tab of the active tab.
    • lastDescendant-of-<Integer:id>: the last descendant tab of the specified tab.
  • senderTab (TST 2.4.9-): the tab containing the content script which calls the API.
  • highlighted (TST 2.6.9-, with Firefox 63 or later) / multiselected (TST 2.6.9-, with Firefox 63 or later): multiselected tabs in the specified or last focused window.
  • allVisibles (TST 4.0-): visible (not hidden, not under any collapsed tree) tabs in the specified or last focused window.
  • normalVisibles (TST 4.0-): visible (not hidden, not under any collapsed tree), and not pinned tabs in the specified or last focused window.

And you can specify more optional parameters states and statesNot to filter results based on tree items' states property. (TST 4.0-)

  • states: an array of state strings. For example states: ["collapsed"] will return collapsed descendant tabs.
  • statesNot: an array of state strings. For example statesNot: ["collapsed"] will return root, expanded descendants, and/or tree parent.

Note:

  • All these aliases are available on TST 2.4.4 and later.
  • All Cyclic suffixed aliases are available on TST 3.2.7 and later.
  • All -of-<id> suffixed aliases are available on TST 3.7.0 and later.

Open new tab bypassing TST's tab control behavior

This is available on TST 3.7.4 or later.

TST is basically designed to work with tabs created by other addons and Firefox itself. However, TST has some options to control position of newly opened tabs from specific triggers and it may break behaviors of your addon. So TST provides an API create: it provides ability for your addon to open a new tab bypassing TST's new tab control behavior. It is compatible to tabs.create(), so it can be used like as:

const params = { url: 'https://example.com/', windowId: 1 };
let tab;
if (useTST)
  tab = await browser.runtime.sendMessage(TST_ID, { type:'create', params });
else
  tab = await browser.tabs.create(params);

Here is the list of available parameters:

This API returns a tree item information. Please remind that you need to get an extra permission to get the returned tab object with some sensitive information, due to security restrictions.

And, please remind that this API completely bypasses TST's tab control including auto-fixup of tree structure, except it is explicitly opened as a child tab of an existing tab. New tabs can be opened at a middle of an existing tree without valid tree structure, so it can break tree management too easily.

Open new child tab from a specific tab

To open new child tab from any existing tab, you just need to specify openerTabId option (available at Firefox 57 and later) for browser.tabs.create(). For example:

let [activeTab, ] = await browser.tabs.query({
  active: true,
  currentWindow: true
});
browser.tabs.create({
  url: 'http://www.example.com/',
  openerTabId: activeTab.id // optional, tabs.Tab.id
});

Of course you can use the create API instead of tabs.create() to open a new child tab.

Indent (demote) tab

This API is available on TST 2.4.4 or later.

indent (and demote) message attaches the specified tab to its previous sibling tab. For example:

let success = await browser.runtime.sendMessage(TST_ID, {
  type:           'indent', // or 'demote'
  tab:            'current', // required, tabs.Tab.id or alias
  followChildren: false // optional, boolean (default=false)
});

If you specify an option followChildren:true, all of descendants are indented together. Otherwise descendants are detached from the specified tab and only the tab is indented.

Outdent (promote) tab

This API is available on TST 2.4.4 or later.

outdent (and promote) message attaches the specified tab to its grand-parent tab. For example:

let success = await browser.runtime.sendMessage(TST_ID, {
  type:           'outdent', // or 'promote'
  tab:            'current', // required, tabs.Tab.id or alias
  followChildren: false // optional, boolean (default=false)
});

If you specify an option followChildren:true, all of descendants are outdented together. Otherwise descendants are detached from the specified tab and only the tab is outdented.

Attach existing tab to another as a child

attach message attaches an existing tab to different tab as its child. For example:

let success = await browser.runtime.sendMessage(TST_ID, {
  type:         'attach',
  parent:       6, // required, tabs.Tab.id or alias
  child:        9, // required, tabs.Tab.id or alias
  insertBefore: 8, // optional, tabs.Tab.id or alias
  insertAfter:  7, // optional, tabs.Tab.id or alias
});

If the new child tab is already attached to different parent, then it is implicitly detached from its old parent.

You can give optional parameter insertBefore and/or insertAfter to control where the attached tab is placed at. Otherwise the attached tab will be placed at top or bottom of existing children.

Detach existing child tab from its parent

detach message detaches a child tab from its parent. For example:

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'detach',
  tab:  9 // required, tabs.Tab.id or alias
});

Note that detached tab (and its descendants) stays there. In other words, if you detach a child tab from a tree, you must move detached tab (and its descendants) to somewhere like after the last tab manually.

Collapse expanded tree

collapse-tree message collapses an existing tree.

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'collapse-tree',
  tab:  2, // required, tabs.Tab.id or alias
  recursively: false // optional, collapse tree recursively or not. false by default.
});

It always succeeds if the tab has no child or it is already collapsed. The recursively option is available on TST 3.4.6 and later.

Expand collapsed tree

expand-tree message expands an existing tree.

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'expand-tree',
  tab:  2, // required, tabs.Tab.id or alias
  recursively: false // optional, expand tree recursively or not. false by default.
});

It always succeeds if the tab has no child or it is already expanded. The recursively option is available on TST 3.4.6 and later.

Toggle collapsed state of tree

This API is available on TST 3.2.7 or later.

toggle-tree-collapsed message toggles collapsed state of an existing tree.

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'toggle-tree-collapsed',
  tab:  2 // required, tabs.Tab.id or alias
});

It always succeeds if the tab has no child.

Set "Locked as Collapsed" state of tree

This API is no longer supported on TST 3.3.7 and later, because the feature was removed and extracted as a helper addon.

This API is available on TST 3.2.7 or later.

You can set "Locked as Collapsed" state of a tree with lock-tree-collapsed and unlock-tree-collapsed message.

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'lock-tree-collapsed',
  tab:  2 // required, tabs.Tab.id or alias
});

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'unlock-tree-collapsed',
  tab:  2 // required, tabs.Tab.id or alias
});

toggle-lock-tree-collapsed message toggles the "Locked as Collapsed" state of an existing tree.

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'toggle-lock-tree-collapsed',
  tab:  2 // required, tabs.Tab.id or alias
});

They always succeed if the tab has no child.

Control sticky state of tabs at tab bar edges

This API is available on TST 4.0 or later.

You can control sticky state of tabs via messages with types stick-tab, unstick-tab, and toggle-sticky-state.

  • stick-tab marks specified tab to be stuck to tab bar edges.
  • unstick-tab unmarks specified tab to be stuck.
  • toggle-sticky-state toggles sticky state of tabs based on the first specified tab.

For example:

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'toggle-sticky-state',
  tab:  2 // required, tabs.Tab.id or alias
});

Please note that this API just marks the tab as "to be stuck" or unmarks, so the tab won't be stuck to tab bar edges while it is in the viewport. The tab will be stuck when it is scrolled out, and unstuck when it moves into the viewport.

See also a notification type to know a tab is stuck or unstuck.

And, there are more message types register-auto-sticky-states and unregister-auto-sticky-states to make tabs with something states sticky automatically. They accepts only one parameter:

  • state (required): An array of strings or a string to be registered/unregistered as "auto sticky state".

Here is an example to make tabs sharing something sticky:

await browser.runtime.sendMessage(TST_ID, {
  type:  'register-auto-sticky-states',
  state: ['sharing-camera', 'sharing-microphone', 'sharing-screen'],
});

Please note that registered states are cleared when the sidebar panel is reloaded, so you need to register them again with sidebar-shown notification.

Set custom tooltip text to tabs

This API is available on TST 4.0 or later.

You can set custom tooltip text to each tab by a message with the type set-tooltip-text. It accepts some parameters:

  • tab (required): A tabs.Tab.id or an alias of the tab to be changed its tooltip text.
  • text (required): A string which should be used as the tooltip text. Blank string means "disable tooltip text".
  • force (optional, default=false): A boolean, indicating the tooltip text to be applied always (true) or applied only when the title is short (false).

For example:

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'set-tooltip-text',
  tab:  2, // required, tabs.Tab.id or alias
  text: tab.url, // use the URL as the tooltip
});

Please note that blank text means "show no tooltip text on the tab". Call clear-tooltip-text instead, if you hope to restore the default tooltip text applied by TST.

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'clear-tooltip-text',
  tab:  2, // required, tabs.Tab.id or alias
});

The final caller will win if multiple addons call these APIs for a specific tab.

Move tree to different position

Basically you don't need to call any TST's API to move tabs. TST is designed compatible to the regular way browser.tabs.move().

  • When a parent tab is moved in same window, all descendant tabs are also moved together automatically.
  • When a parent tab is moved across windows, all descendant tabs are left in the source window. In this case, if you hope that a whole tree is moved to different window, then you need to move descendant tabs to the destination window and restructure tree manually.

But this compatibility mechanism is fragile. If an addon moves multiple tabs in a time, TST sometimes fails to fixup the tree structure of moved tabs. So, there are some APIs for safety: commands to move tabs with their structure, and a hook to cancel the autofixing.

Here is a list of command type APIs:

  • move-up (available on TST 2.4.4 and later) moves a solo tab or a tree upward. This accepts some parameters:

    • tab (required): A tabs.Tab.id or an alias of the tab to be moved.
    • followChildren (optional, default=false): A boolean, indicating the move mode. true means "move a tree", false means "move a solo tab without its children".

    For example:

    // move a tree upward
    let success = await browser.runtime.sendMessage(TST_ID, {
      type:           'move-up',
      tab:            'current',
      followChildren: true
    });
  • move-down (available on TST 2.4.4 and later) moves a solo tab or a tree downward. This accepts some parameters:

    • tab (required): A tabs.Tab.id or an alias of the tab to be moved.
    • followChildren (optional, default=false): A boolean, indicating the move mode. true means "move a tree", false means "move a solo tab without its children".

    For example:

    // move a tree downward
    let success = await browser.runtime.sendMessage(TST_ID, {
      type:           'move-down',
      tab:            'current',
      followChildren: true
    });
  • move-before (available on TST 2.8.0 and later) moves a solo tab or a tree before a reference tab. This accepts some parameters:

    • tab (required): A tabs.Tab.id or an alias of the tab to be moved.
    • referenceTabId (required): A tabs.Tab.id of the reference tab which the tab should be placed before.
    • followChildren (optional, default=false): A boolean, indicating the move mode. true means "move a tree", false means "move a solo tab without its children".

    For example:

    // move a tree before the tab 8
    let success = await browser.runtime.sendMessage(TST_ID, {
      type:           'move-before',
      tab:            'current',
      referenceTabId: 4,
      followChildren: true
    });
  • move-after (available on TST 2.8.0 and later) moves a solo tab or a tree after a reference tab. This accepts some parameters:

    • tab (required): A tabs.Tab.id or an alias of the tab to be moved.
    • referenceTabId (required): A tabs.Tab.id of the reference tab which the tab should be placed after.
    • followChildren (optional, default=false): A boolean, indicating the move mode. true means "move a tree", false means "move a solo tab without its children".

    For example:

    // move a tree after the tab 8
    let success = await browser.runtime.sendMessage(TST_ID, {
      type:           'move-after',
      tab:            'current',
      referenceTabId: 8,
      followChildren: true
    });
  • move-to-start (available on TST 2.6.9 and later) This will help you to simulate the "Move Tabs" => "Move to Start" command of the tab context menu, safely with tree structure. This accepts some parameter:

    • tab (optional, alias tabId): A tabs.Tab.id or an alias of a tab or tabs to be moved.
    • tabs (optional, alias tabIds): An array of tabs.Tab.id or alias of tabs to be moved.

    One of tab, tabId, tabs or tabIds is required. For example:

    // move all highlighted tabs to the start
    let success = await browser.runtime.sendMessage(TST_ID, {
      type: 'move-to-start',
      tab:  'highlighted'
    });
  • move-to-end (available on TST 2.6.9 and later) moves specified tabs to the end of the tab bar. This will help you to simulate the "Move Tabs" => "Move to End" command of the tab context menu, safely with tree structure. This accepts some parameter:

    • tab (optional, alias tabId): A tabs.Tab.id or an alias of a tab or tabs to be moved.
    • tabs (optional, alias tabIds): An array of tabs.Tab.id or alias of tabs to be moved.

    One of tab, tabId, tabs or tabIds is required. For example:

    // move all highlighted tabs to the end
    let success = await browser.runtime.sendMessage(TST_ID, {
      type: 'move-to-end',
      tab:  'highlighted'
    });

And you can also cancel TST's tree autofixing for moved tabs. See the description of try-fixup-tree-on-tab-moved also.

Focus to the next/previous sibling tab

This API is available on TST 2.4.4 or later.

focus message focuses to the specified tab. For example:

let success = await browser.runtime.sendMessage(TST_ID, {
  type:     'focus',
  tab:      'nextSibling', // required, tabs.Tab.id or alias
  silently: false // optional, boolean (default=false)
});

The tab parameter accepts alias name of tabs, so nextSibling will focus to the next sibling tab, previousSibling will focus to the previous sibling tab.

If you specify an option silently:true, children of focused tab will be kept collapsed. Otherwise TST expands the tree of focused tab automatically. Combinations with tab aliases nextVisible and previousVisible should allow you to move focus only around visible (not collapsed) tabs, on TST 3.2.7 and later.

Duplicate tab as child/sibling tab

This API is available on TST 2.4.4 or later.

duplicate message duplicates the specified tab at the specified position. For example:

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'duplicate',
  tab:  'current', // required, tabs.Tab.id or alias
  as:   'child' // optional, string
});

Here is the list of available value for the as option:

  • sibling: duplicated tab will be placed just next to the source tab.
  • nextSibling: duplicated tab will be placed as the next sibling of the source tab.
  • first-child (available on TST 3.9.20 or later): duplicated tab will be placed as the fist child of the source tab.
  • last-child (available on TST 3.9.20 or later): duplicated tab will be placed as the last child of the source tab.
  • child: duplicated tab will be placed as a child of the source tab. On TST 3.9.20 or later, this respects TST's configuration for duplicated tabs if it is configured as "first child" or "last child".
  • orphan (default on TST 2.6.8 or olders): duplicated tab will be placed at the end of the tab bar.

On TST 2.6.9 or later, the default behavior of the as option respects TST's configuration for duplicated tabs.

Move tabs to a new window (opening new window from tabs)

This API is available on TST 2.6.9 or later.

open-in-new-window type message moves specified tabs to a new window. For example:

let windowId = await browser.runtime.sendMessage(TST_ID, {
  type: 'open-in-new-window',
  tab:  'highlighted', // required, tabs.Tab.id or alias
});

The result is the ID of the newly opened window. It will help you to simulate "Move Tabs" => "Move Tabs to New Window" command of the tab context menu, safely with tree structure.

Reopen tabs in a container

This API is available on TST 2.6.9 or later.

reopen-in-container type message reopens specified tabs with the container. For example:

let reopenedTabs = await browser.runtime.sendMessage(TST_ID, {
  type:        'reopen-in-container',
  tab:         'highlighted', // required, tabs.Tab.id or alias
  containerId: 'firefox-container-1' // optional, 'firefox-default' by default
});

The parameter containerId is a valid ID of a contextual identity, appearing as tabs.Tab.cookieStoreId.

The result is the new tabs reopened in the container. It will help you to simulate "Reopen in Container" command of the tab context menu, safely with tree structure.

Create new group from given tabs

This API is available on TST 2.4.4 or later.

group-tabs message creates a new tree from specified tabs. Tabs will be grouped under a dummy parent tab. For example:

let parentTab = await browser.runtime.sendMessage(TST_ID, {
  type: 'group-tabs',
  title: 'New Group', // optional, title of the created group tab (available on TST 3.9.13 and later)
  tabs: [1, 2, 3], // required, array of tabs.Tab.id or alias
});

TST 4.0.19 and later supports temporary and temporaryAggressive boolean options, to control checkboxes in the group tab.

// Close the group tab when there is no child tab
let parentTab = await browser.runtime.sendMessage(TST_ID, {
  type: 'group-tabs',
  title: 'New Group',
  tabs: [1, 2, 3],
  temporary: true,
});

// Close the group tab when there is only one child tab is left
let parentTab = await browser.runtime.sendMessage(TST_ID, {
  type: 'group-tabs',
  title: 'New Group',
  tabs: [1, 2, 3],
  temporaryAggressive: true,
});

// Never close the group tab even if there is no child tab
let parentTab = await browser.runtime.sendMessage(TST_ID, {
  type: 'group-tabs',
  title: 'New Group',
  tabs: [1, 2, 3],
  temporary: false,
  temporaryAggressive: false,
});

Close whole tree

There is no specific API to close all tabs in a tree by just one operation. Please use browser.tabs.remove() simply to close tree of tabs.

  • When a closing parent tab has collapsed children, all descendants are also closed together automatically.
  • When a closing parent tab has expanded children, the first child tab is promoted as the new parent. In this case, if you hope that a whole expanded tree is closed, then you need to collapse the tree at first or close all descendant tabs manually.

Scroll the tab bar

This API is available on TST 2.0.2 or later.

scroll message scrolls the tab bar.

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'scroll',
  ...
});

There are three forms of its usage:

  • Scrolling to a tab. In this form, you must specify an ID of a tab, like:

    let success = await browser.runtime.sendMessage(TST_ID, {
      type: 'scroll',
      tab:  2 // integer, an ID of a tab
    });

    Note that this does nothing if the specified tab is already visible.

  • Scrolling to absolute position. In this form, you must specify an ID of a window and absolute position, like:

    let success = await browser.runtime.sendMessage(TST_ID, {
      type:     'scroll',
      window:   3,  // integer, an ID of a window
      position: 250 // integer, an absolute scroll position in pixels / string, an CSS length (TST 3.7.5 and later)
    });

    On TST 3.2.7 and later, a special ID string active is available to specify the active browser window, like:

    let success = await browser.runtime.sendMessage(TST_ID, {
      type:     'scroll',
      window:   'active',
      position: 250
    });
  • Scrolling by relative delta. In this form, you must specify an ID of a window and delta, like:

    let success = await browser.runtime.sendMessage(TST_ID, {
      type:   'scroll',
      window: 3,  // integer, an ID of a window
      delta:  -20 // integer, a relative scroll in pixels / string, an CSS length (TST 3.7.5 and later)
    });

    On TST 3.2.7 and later, a special ID string active is available to specify the active browser window, like:

    let success = await browser.runtime.sendMessage(TST_ID, {
      type:   'scroll',
      window: 'active',
      delta:  -20
    });
  • Scrolling slowly (available on TST 3.7.5 and later). You can specify the scroll duration via the duration option, like:

    let success = await browser.runtime.sendMessage(TST_ID, {
      type:     'scroll',
      window:   3,
      delta:    3000,
      duration: 10 * 1000 // integer, in milliseconds. 1000 msec equals to 1 sec.
    });

    In-progress scroll with large duration can be canceled with the stop-scroll API like as:

    let success = await browser.runtime.sendMessage(TST_ID, {
      type:   'stop-scroll',
      window: 3
    });

On TST 3.7.5 and later position and delta accept any CSS length like 123px, 4em, 0px - var(--tab-size) * 3, and others.

Take a tree structure snapshot of tabs

You can get structure information of given tabs with a message with the type get-tree-structure. It returns an array object indicating tree structure of tabs specified with tab/tabId/tabs/tabIds and window/windowId parameters (compatible to get-tree's parameters). For example:

// Get tree structure of entire tabs in the window 1.
const structure1 = await browser.runtime.sendMessage(TST_ID, {
  type:   'get-tree-structure',
  tabs:   '*',
  window: 1
});

// Get tree structure of only some tabs.
const structure2 = await browser.runtime.sendMessage(TST_ID, {
  type: 'get-tree-structure',
  tabs: [1,2,3,4]
});

The returned object is available for the structure parameter of a message with the type set-tree-structure. It is an array of objects with following properties:

  • parent: An integer, indicating the index of its parent tab. For more details see the description below.
  • collapsed: A boolean, indicating that its subtree is collapsed (true) or expanded (false).
  • id: The ID string internally used by TST. It is different from Tab.id generally used in WebExtensions APIs. This is exposed for internal use, so you should ignore it.

It is little hard to describe what the value of parent means. For example assume that given tabs have a tree structure like this:

* Tab A         \
  * Tab A-1      | Tree X
    * Tab A-1-1  |
  * Tab A-2     /
* Tab B         \
  * Tab B-1      | Tree Y
  * Tab B-2     /
* Tab C         -- Tree Z

Then get-tree-structure will return a result like:

[
  { parent: -1, collapsed: true, id: '...' }, // Tab A     \
  { parent:  0, collapsed: true, id: '...' }, // Tab A-1    | Tree X
  { parent:  1, collapsed: true, id: '...' }, // Tab A-1-1  |
  { parent:  0, collapsed: true, id: '...' }, // Tab A-2   /
  { parent: -1, collapsed: true, id: '...' }, // Tab B     \
  { parent:  0, collapsed: true, id: '...' }, // Tab B-1    | Tree Y
  { parent:  0, collapsed: true, id: '...' }, // Tab B-2   /
  { parent: -1, collapsed: true, id: '...' }  // Tab C     -- Tree Z
]

There are three root tabs [A, B, C] and corresponding three trees [X, Y, Z]. The value of parent indicates the index of the tab in the tree belonging to, as:

  • The tab A has no parent in the tree X so its parent is -1.
  • The parent of the tab A-1 is A, the first tab in the tree X. So the parent of A-1 is 0.
  • The parent of the tab A-1-1 is A-1, the second tab in the tree X. So the parent of A-1-1 is 1.
  • The parent of the tab A-2 is A, so the parent of A-2 is 0.
  • The tab B has no parent in the tree Y so its parent is -1.
  • The parent of the tab B-1 is B, the first tab in the tree Y. So the parent of B-1 is 0.
  • ...

Apply a tree structure to tabs

You can set tree structure of given tabs with a message with the type set-tree-structure with just one API call. The target tabs are specified with tab/tabId/tabs/tabIds and window/windowId parameters (compatible to get-tree's parameters), and the structure of tabs is specified with the object respond by the get-tree-structure API or a simplified version of it.

For example:

// Case 1: get tree structure of entire tabs in the window 1,
const structure1 = await browser.runtime.sendMessage(TST_ID, {
  type:   'get-tree-structure',
  tabs:   '*',
  window: 1
});
// and apply the structure to tabs in the window 2.
browser.runtime.sendMessage(TST_ID, {
  type:      'set-tree-structure',
  tabs:      '*',
  window:    2,
  structure: structure1
});

// Case 2: create a structure like a group (one parent and other children).
// This is same to an array of `parent` extracted from the result of `get-tree-structure`
const structure2 = [-1, 0, 0, 0];
browser.runtime.sendMessage(TST_ID, {
  type:      'set-tree-structure',
  tabs:      [1,2,3,4],
  structure: structure2
});

Extra tabs or structure information are cut off if the number of tabs and the length of the structure information is not same.

Get tree information

Data format

TST API provides ability to get tree information. Each tree item is presented as an object with following properties:

  • id: an integer, the id of the tab.
  • windowId: an integer, the windowId of the tab.
  • states: an array of TST-specific states applied to the tab. Possible values are:
    • collapsed: The tab is in a collapsed subtree. The tab is invisible.
    • subtree-collapsed: The tab has any child, and its subtree is collapsed. All child tabs are invisible.
    • locked-collapsed: The subtree of the tab is locked as collapsed. (Available on TST 3.2.7 and later.)
    • group-tab: A special class on a dummy tab for grouping.
    • creating: The tab is in the creating process. (Available on TST 4.0 and later.)
    • newtab-command-tab: The tab is detected as a tab opened from any "New Tab" command. (Available on TST 4.0 and later.)
    • duplicated: The tab is detected as a tab duplicated from any other tab. (Available on TST 4.0 and later.)
    • restored: The tab is detected as a tab reopened from Ctrl-Shift-T or something other triggers. (Available on TST 4.0 and later.)
    • from-external: The tab is detected as a tab opened from any external application. (Available on TST 4.0 and later.)
    • from-firefox-view: The tab is detected as a tab opened from Firefox View. (Available on TST 4.0 and later.)
    • opened-for-same-website: The tab is detected as a tab opened with a URL which the domain is same to the active tab. (Available on TST 4.0 and later.)
    • sticky: The tab is marked to be stuck to tab bar edges. (Available on TST 4.0 and later.)
    • stuck: The tab is really stuck to one of tab bar edges. Note that this state is presented only when the information is given from the visible sidebar panel, e.g. a part of a try-scroll-to-activated-tab notification. (Available on TST 4.0.23 and later.)
  • indent: the indent level of the tab (integer). It is 0 for top level tabs. (Note: this property is available on Tree Style Tab 2.4.8 and later.)
  • children: an array of child tabs with same format (extended tabs.Tab) recursively.
  • ancestorTabIds: an array of ancestor tabs' tabs.Tab.id (integer). The first item is the direct parent of the tab, the last item is the root level parent. (Note: this property is available on Tree Style Tab 2.4.17 and later.)
  • bundledTabId: the bundled tab's tabs.Tab.id (integer). If the tab has no bundled tab, this becomes -1. (Note: this property is available on Tree Style Tab 3.2.6 and later.) What the bundled tab is:
    • For a pinned tab, the related group tab opened to group regular child tabs opened from the pinned tab.
    • For a group tab, the related pinned tab which is the real parent tab of children tabs under the group tab itself.

On TST 4.0 and later, "Light tree", responses for get-light-tree request or tab-like properties contained in notifications to an addon registered with an option lightTree:true, will have only properties described above. "Full tree", responses for get-tree request or tab-like properties contained in notifications to an addon registered without lightTree:true, will have more properties corresponding to ones of tabs.Tab object except title, url, favIconUrl, and cookieStoreId.

For example:

browser.runtime.sendMessage(TST_ID, { type: 'get-light-tree', tabId: 2 });
=>
{ id: 2,
  windowId: 1,
  states: [],
  indent: 0,
  ancestorTabIds: [],
  children: [
    { id: 3,
      windowId: 1,
      states: [],
      indent: 1,
      ancestorTabIds: [2],
      children: [] },
    { id: 4,
      windowId: 1,
      states: ["subtree-collapsed"],
      indent: 1,
      ancestorTabIds: [2],
      children: [
        { id: 5,
          windowId: 1,
          states: ["collapsed"],
          indent: 2,
          ancestorTabIds: [4, 2],
          children: [] }
      ] }
  ] }

browser.runtime.sendMessage(TST_ID, { type: 'get-tree', tabId: 2 });
=>
{ id: 2,
  windowId: 1,
  pinned: false, // from tabs.Tab
  attention: false, // from tabs.Tab
  ... // more other properties are available
  states: [],
  indent: 0,
  ancestorTabIds: [],
  children: [
    { id: 3,
      windowId: 1,
      pinned: false,
      attention: false,
      ...
      states: [],
      indent: 1,
      ancestorTabIds: [2],
      children: [] },
    ...
  ] }

On TST 3.0.12 and later, you need to call tabs.get(), tabs.query() or other WebExtensions APIs to get full tab information of tree items. However, if your addon has special permissions, each tree item will have more properties inherited from the tabs.Tab object corresponding to it.

(In other words, on TST 3.0.11 or older versions, each tree item always had properties inherited from tabs.Tab object corresponding to it, and more information was exposed via its states property. This spec violated WebExtensions's security model, so now they are hidden by default.)

Here is an example implementation to resolve tree items to tabs without special permissions:

async function resolveTreeItemToTab(treeItem, windowId) {
  if (!treeItem)
    return treeItem;
  const tabs = await browser.tabs.query({ windowId });
  const tabsById = new Map();
  for (const tab of tabs) {
    tabsById.set(tab.id, tab);
  }
  const resolve = (tab) => {
    if (tab.children)
      tab.children = tab.children.map(resolve);
    return Object.assign(tabsById.get(tab.id), tab);
  };
  return resolve(treeItem);
}

APIs to get tree information

There are APIs get-tree and get-light-tree, to collect tab information with their tree structure. For descriptions, now we assume that there a set of tabs with tree structure:

  • Window A (id:1)
    • Tab A (id:1, pinned)
    • Tab B (id:2, active)
      • Tab B-a (id:3)
      • Tab B-b (id:4, collapsed)
        • Tab B-b-1 (id:5)
    • Tab C (id:6, collapsed, out of the viewport)
      • Tab C-a (id:7, out of the viewport)

Get tree information for specific single tab

You should give the ID of a tab via the tab parameter, to get tree information of single tab. For example:

let tab = await browser.runtime.sendMessage(TST_ID, {
  type: 'get-light-tree',
  tab:  2
});
/* tab =>
{ id: 2, ...
  states: [],
  indent: 0,
  children: [
    { id: 3, ...
      states: [],
      indent: 1,
      children: [],
      ancestorTabIds: [2] },
    { id: 4, ...
      states: ["subtree-collapsed"],
      indent: 1,
      children: [
        { id: 5, ...
          states: ["collapsed"],
          indent: 2,
          children: [],
          ancestorTabIds: [4, 2] }
      ],
      ancestorTabIds: [2] }
  ],
  ancestorTabIds: [] }
*/

Get tree information for specific multiple tabs

You should give an array of IDs of tabs via the tabs/tabIds parameter, to get tree information of multiple tab at a time. For example:

let tabs = await browser.runtime.sendMessage(TST_ID, {
  type: 'get-light-tree',
  tabs:  [1, 2]
});
/* tabs =>
[
  { id: 1, ...
    children: [] },
  { id: 2, ...
    children: [...] }
]
*/

Get tree information for all tabs in a specific window

You should give an window ID via the window parameter, to get clear tree information of a window at a time. For example:

let tabs = await browser.runtime.sendMessage(TST_ID, {
  type:   'get-light-tree',
  window: 1
});
/* tabs =>
[
  { id: 1, ... },
  { id: 2, ...
    children: [
      { id: 3, ... },
      { id: 4, ...
        children: [
          { id: 5, ... }
        ] }
    ] },
  { id: 6, ...
    children: [
      { id: 7, ... }
    ] }
]
*/

Note that only root tabs appear in the array (id=1, 2, 6). As the result, you need to scan children of each tab to retrieve all tabs. If you hope to get a flat list of all tabs in the current window, see the next section.

Get tree information for all tabs in a window, as a flat array

You should give a string * via tab, tabId, tabs or tabIds parameter, to get tree information of all tabs at a time as a flat array. For example:

let tabs = await browser.runtime.sendMessage(TST_ID, {
  type:   'get-light-tree',
  window: 1,
  tabs:   '*'
});
/* tabs =>
[
  { id: 1, ... },
  { id: 2, ...
    children: [
      { id: 3, ... },
      { id: 4, ...
        children: [
          { id: 5, ... }
        ] }
    ] },
  { id: 3, ... },
  { id: 4, ...
    children: [
      { id: 5, ... }
    ] },
  { id: 5, ... },
  { id: 6, ...
    children: [
      { id: 7, ... }
    ] },
  { id: 7, ... }
]
*/

Note that some tabs appear multiple times (id=3, 4, 5, 7). This is because the wildcard * always collects tree information from all tabs. If you don't need such duplicated information, see the previous section.

If you omit the window parameter, tabs in the last focused window will be returned.

Get tree information for only rendered tabs

For better performance, only in-viewport tabs are actually rendered, and they are un-rendered when they go away from the viewport, on TST 4.0 and later. You can get tree information for already rendered tabs with a boolean parameter rendered: true, for example:

let tabs = await browser.runtime.sendMessage(TST_ID, {
  type:   'get-light-tree',
  window: 1,
  tabs:   '*',
  rendered: true,
});
/* tabs =>
[
  { id: 1, ... }, // pinned tabs are always rendered
  { id: 2, ... },
  { id: 3, ... },
  { id: 4, ... },
  // id=5 tab is not rendered because it is under a collapsed tree
  // id=6 and id=7 are out of the viewport
]
*/

Override reaction for mouse wheel rotation on the vertical tab bar

By default, mouse wheel simply scrolls the tab bar. If you hope to override the behavior, you need to lock the scroll and do something based on notified messages.

Stop and restart scrolling of the tab bar

This API is available on TST 2.0.2 or later.

scroll-lock message disables the default scrolling behavior.

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'scroll-lock'
});

On the other hand, scroll-unlock message enables the default scrolling behavior again.

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'scroll-unlock'
});

Multiple addons can lock the scroll at a time, and TST never produce the default scrolling behavior while it is locked by any addon even if your addon already unlocks. In other words, you must not forget to unlock the scroll before your addon is completely unloaded (disabled or uninstalled).

Messages notified by mouse wheel rotation

This API is available on TST 2.0.2 or later.

While your addon locks the scrolling, TST notifies scrolled message to your addon.

browser.runtime.onMessageExternal.addListener((message, sender) => {
  switch (sender.id) {
    case TST_ID:
      switch (message.type) {
        ...
        case 'scrolled':
          // do something here. for example:
          let tab = getNextFocusedTab(message.tabs);
          browser.tabs.update(tab.id, { active: true });
          return Promise.resolve(true); // you must return any non-undefined value.
        ...
      }
      break;
  }
});

Here is a list of properties notified message have:

  • tab: A tree item corresponding to the tab you rotated the mouse wheel on.
  • tabs: A flatten array of tree items corresponding to tabs in the window. This quite equals to the result of get-tree with tabs:'*'.
  • window (alias windowId): An integer, the owner window's ID.
  • overflow: A boolean, meaning the tab bar is scrollable or not. (available on TST 3.8.9 and later)
  • deltaX: A number, the value of WheelEvent#deltaX. (Available on TST 3.2.6 and later.)
  • deltaY: A number, the value of WheelEvent#deltaY.
  • deltaZ: A number, the value of WheelEvent#deltaZ. (Available on TST 3.2.6 and later.)
  • deltaMode: An integer, the value of WheelEvent#deltaMode.
  • scrollTop: An integer, the current scroll position of the tab bar.
  • scrollTopMax: An integer, the maximum scroll position of the tab bar.
  • altKey: A boolean, the Alt modifier key is pressed or not.
  • ctrlKey: A boolean, the Ctrl (Control) modifier key is pressed or not.
  • metaKey: A boolean, the Meta (Command on macOS) modifier key is pressed or not.
  • shiftKey: A boolean, the Shift modifier key is pressed or not.
  • clientX: An integer, the value of MouseEvent#clientX indicating the coordinate the event fired at.
  • clientY: An integer, the value of MouseEvent#clientY indicating the coordinate the event fired at.

Based on these information, you'll scroll the tab bar with custom algorithm or any other reactions.

You must return any non-undefined value (including false, 0, and so on) from the listener. Otherwise TST guesses the listener addon is already unloaded and unlocks the scroll for your addon automatically.

APIs to set custom state for tabs

You can set custom state to tabs via messages with add-tab-state and remove-tab-state type. Custom classes will appear as classes of tab elements like <li class="tab active myaddon-marked">, so you can apply any style definitions to tabs.

Note that all built-in states and custom states are mixed into the same namespace, so you can break TST's functions easily if you modify TST's built-in states. For safety, prefixed names like myaddon-marked instead of simple names like marked are recommended.

And, please note that custom states won't be exposed via the states property of any tree item for security reasons, on TST 3.0.12 or later. (On TST 3.0.11 or older versions all extra stats and built-in states were exposed, but now they are unavailable.)

Add state(s)

A message with the type add-tab-state adds given states to specified tabs as their classes. For example:

browser.runtime.sendMessage(TST_ID, {
  type:  'add-tab-state',
  tabs:  [1, 2, 3], // required, an array of tabs.Tab.id or alias
  state: 'my-selected' // required, a state string or an array of state strings
});

You can specify multiple states at a time:

browser.runtime.sendMessage(TST_ID, {
  type:  'add-tab-state',
  tabs:  [1, 2, 3],
  state: ['my-selected', 'my-another-custom-status']
});

Remove state(s)

A message with the type remove-tab-state removes given states from specified tabs. For example:

browser.runtime.sendMessage(TST_ID, {
  type:  'remove-tab-state',
  tabs:  [1, 2, 3], // required, an array of tabs.Tab.id or alias
  state: 'my-selected' // required, a state string or an array of state strings
});

You can specify multiple states at a time:

browser.runtime.sendMessage(TST_ID, {
  type:  'remove-tab-state',
  tabs:  [1, 2, 3],
  state: ['my-selected', 'my-another-custom-status']
});

Notification messages from TST

TST sends notification messages to registered addons. To receive these messages, you need to register your addon at first.

When the TST itself is initialized

A message with the type ready will be notified, when the TST itself is initialized. For more details, see another section: how to register your addon.

When the TST sidebar is shown/hidden

This API is available on TST 2.4.23 or later.

There are two notification message types: sidebar-show and sidebar-hide.

  • A message with the type sidebar-show will be notified when the TST sidebar is shown.
  • A message with the type sidebar-hide will be notified when the TST sidebar is hidden.

Here is a list of properties these type message objects commonly have:

  • window (alias windowId): An integer, the owner window's ID for the sidebar.

On TST 3.0.12 and later, this notification won't be delivered if it happens on a private window and your addon is not allowed for private windows.

When any context menu item is clicked

When a context menu item added by your addon is clicked, your addon will receive a notification message with the type contextMenu-click. For more details, see another section.

This message will be delivered to your addon even if you don't list this at the listeningTypes parameter for the register-self message.

On TST 3.0.12 and later, this notification won't be delivered if it happens on a private window and your addon is not allowed for private windows.

When the context menu is opened and closed

This API is available on TST 2.4.25 or later.

A message with the type contextMenu-shown will be notified, when the context menu is going to be opened. It corresponds to the browser.menus.onShown. See another section for more details.

And, another message with the type contextMenu-hidden will be notified, when the context menu is closed. It corresponds to the browser.menus.onHidden.

These type messages won't be delivered to your addon implicitly. You need to list them at the listeningTypes parameter for the register-self message.

On TST 3.0.12 and later, this notification won't be delivered if it happens on a private window and your addon is not allowed for private windows.

When the TST finishes its handling for a newly opened tab

This API is available on TST 3.8.24 or later.

When a tab is opened by TST or others, TST handles it and attaches to existing tree based on its context or doesn't. After all handling by TST is finished, a notification message with the type new-tab-processed will be delivered to listeners. Here is a list of properties the message object has:

  • tab: A tree item corresponding to the tab newly opened.
  • restored: A boolean, indicating the tab is restored from session information (ex. Ctrl-Shift-T) or not.
  • duplicated: A boolean, indicating the tab is duplicated from another tab or not.
  • originalTab: A tree item corresponding to the original tab, if it is duplicated.
  • fromExternal: A boolean, indicating the tab is guessed as opened by another application. Please note that this is based on situational evidences and it can be misdetected.

This will help you to implement something helper addon working for new tabs opened at the root level: it can be detected like as notifiedMessage.tab.ancestorTabIds.length == 0.

This notification won't be delivered if it happens on a private window and your addon is not allowed for private windows.

When one or more tabs are rendered/un-rendered

This API is available on TST 4.0 and later.

For better performance, only in-viewport tabs are actually rendered, and they are un-rendered when they go away from the viewport, on TST 4.0 and later. Notification message with types tabs-rendered or tabs-unrendered will be delivered to listeners, when rendered status of one or more tabs are changed. Here is a list of properties the message object has:

  • tabs: An array of tree items corresponding to the tabs newly rendered or un-rendered.

When a tab is clicked

Messages with tab-mousedown, tab-mouseup, tab-clicked (and tab-dblclicked) types will be delivered to listeners, when any tab is clicked (or double-clicked). Here is a list of properties the message object has:

  • tab: A tree item corresponding to the clicked tab.
  • window (alias windowId): An integer, the owner window's ID.
  • button: An integer to indicate the clicked button. 0=left button, 1=middle button (2 won't be notified)
  • ctrlKey: A boolean, the Ctrl (Control) modifier key is pressed or not.
  • shiftKey: A boolean, the Shift modifier key is pressed or not.
  • altKey: A boolean, the Alt modifier key is pressed or not.
  • metaKey: A boolean, the Meta (Command on macOS) modifier key is pressed or not.
  • closebox: A boolean, the event happens on the closebox or not.
  • sharingState: A boolean, the event happens on the sharing state icon or not. (This property is available on TST 4.0 or later.)
  • soundButton: A boolean, the event happens on the mute/unmute button or not. (This property is available on TST 2.5.3 or later.)
  • twisty: A boolean, the event happens on the twisty or not. (This property is available on TST 2.7.8 or later.)
  • originalTarget (deprecated): A string, indicate the operated extra tab contents inserted via Extra Tab Contents API. (This property is available on TST 3.3.7 or later and deprecated at TST 3.9.0. Currently it is left for backward compatibility.)

If any addon responds to the message with a boolean value true, TST's default behavior (activating the tab) will be canceled. (On TST 2.7.8 and later, returning true for clicking on twisty, closebox, and sound button also cancels default behavior for each button.) For example:

browser.runtime.onMessageExternal.addListener((message, sender) => {
  switch (sender.id) {
    case TST_ID:
      switch (message.type) {
        ...
        case 'tab-clicked':
          let focusChanged = ...; // you'll do something here
          return Promise.resolve(focusChanged);
        ...
      }
      break;
  }
});

On TST 3.0.12 and later, this notification won't be delivered if it happens on a private window and your addon is not allowed for private windows.

When the new tab button is clicked

This API is available on TST 3.8.2 or later.

Messages with new-tab-button-mousedown, new-tab-button-mouseup and new-tab-button-clicked types will be notified, when the new tab button is clicked. Here is a list of properties the message object has:

  • window (alias windowId): An integer, the owner window's ID.
  • button: An integer to indicate the clicked button. 0=left button, 1=middle button (2 won't be notified)
  • ctrlKey: A boolean, the Ctrl (Control) modifier key is pressed or not.
  • shiftKey: A boolean, the Shift modifier key is pressed or not.
  • altKey: A boolean, the Alt modifier key is pressed or not.
  • metaKey: A boolean, the Meta (Command on macOS) modifier key is pressed or not.
  • originalTarget (deprecated): A string, indicate the operated extra tab contents inserted via Extra Tab Contents API. (Deprecated at TST 3.9.0. Currently it is left for backward compatibility.)

If any addon responds to the message with a boolean value true, TST's default behavior (open new tab) will be canceled. For example:

browser.runtime.onMessageExternal.addListener((message, sender) => {
  switch (sender.id) {
    case TST_ID:
      switch (message.type) {
        ...
        case 'new-tab-button-clicked':
          let overrideActionDone = ...; // you'll do something here
          return Promise.resolve(overrideActionDone);
        ...
      }
      break;
  }
});

This notification won't be delivered if it happens on a private window and your addon is not allowed for private windows.

When the non-tab area is clicked

Messages with tabbar-mousedown, tabbar-mouseup and tabbar-clicked types will be notified, when the non-tab area is clicked. Here is a list of properties the message object has:

  • window (alias windowId): An integer, the owner window's ID.
  • button: An integer to indicate the clicked button. 0=left button, 1=middle button (2 won't be notified)
  • isMiddleClick: A boolean indicating if a middle click was performed.
  • ctrlKey: A boolean, the Ctrl (Control) modifier key is pressed or not.
  • shiftKey: A boolean, the Shift modifier key is pressed or not.
  • altKey: A boolean, the Alt modifier key is pressed or not.
  • metaKey: A boolean, the Meta (Command on macOS) modifier key is pressed or not.

If any addon responds to the message with a boolean value true, TST's default behavior (add new tab) will be canceled. (TST 2.0.5 or later)

On TST 3.0.12 and later, this notification won't be delivered if it happens on a private window and your addon is not allowed for private windows.

When the pointer is moved over tabs

This API is available on TST 2.4.19 or later.

Following type messages can be delivered to your addon by moving pointer over tabs:

  • tab-mousemove corresponds to mousemove event on tabs.
  • tab-mouseover corresponds to mouseover event on tabs. This won't be delivered again and again for same tab.
  • tab-mouseout corresponds to mouseout event on tabs. This won't be delivered again and again for same tab.

Here is a list of properties these type message objects commonly have:

  • window (alias windowId): An integer, the owner window's ID.
  • tab: A tree item corresponding to the clicked tab.
  • ctrlKey: A boolean, the Ctrl (Control) modifier key is pressed or not.
  • shiftKey: A boolean, the Shift modifier key is pressed or not.
  • altKey: A boolean, the Alt modifier key is pressed or not.
  • metaKey: A boolean, the Meta (Command on macOS) modifier key is pressed or not.
  • dragging: A boolean, a dragging operation (started by long-press) is in progress or not.

These type messages won't be delivered to your addon implicitly. You need to list them at the listeningTypes parameter for the register-self message.

On TST 3.0.12 and later, this notification won't be delivered if it happens on a private window and your addon is not allowed for private windows.

When the tab bar becomes scrollable or unscrollable

This API is available on TST 3.8.9 or later.

There are two notification message types tabbar-overflow and tabbar-underflow to know changes of the overflow state of the vertical tab bar.

  • A message with the type tabbar-overflow will be notified when the tab bar becomes scrollable for too many tabs or too small window height.
  • A message with the type tabbar-underflow will be notified when the tab bar becomes unscrollable for less tabs or very large window height.

Here is a list of properties these type message objects commonly have:

  • windowId: An integer, the owner window's ID.

When tree structure is modified

This API is available on TST 3.0.12 or later.

There are two notification message types tree-attached and tree-detached to know changes around the tree structure.

  • A message with the type tree-attached will be notified when a tab is attached to an existing another tab.
  • A message with the type tree-detached will be notified when a child tab is detached from a parent tab.

Here is a list of properties these type message objects commonly have:

  • tab: A tree item corresponding to the "child" tab, attached or detached.

tree-attached type messages specially have more properties:

  • parent: A tree item corresponding to the "parent" tab, the child tab is attached to. Its children may have the tab itself.

On the other hand, tree-detached type messages specially have more properties:

  • oldParent: A tree item corresponding to the "parent" tab, the child tab is detached from.

On TST 3.0.12 and later, this notification won't be delivered if it happens on a private window and your addon is not allowed for private windows.

When tree is collapsed or expanded

This API is available on TST 3.3.7 or later.

When a tree is collapsed or expanded, a notification message with the type tree-collapsed-state-changed will be delivered to listeners. The message object will have properties:

  • tab: A tree item corresponding to the tab, collapsed or expanded its subtree.
  • collapsed: A boolean, indicating the tree is collapsed (true) or expanded (false).

This notification won't be delivered if it happens on a private window and your addon is not allowed for private windows.

When a tab is stuck or unstuck to/from tab bar edges

This API is available on TST 4.0 or later.

When a tab is marked to be stuck or unmarked, a notification message with the type tab-sticky-state-changed will be delivered to listeners. The message object will have properties:

  • tab: A tree item corresponding to the tab which is changed its sticky state.
  • sticky: A boolean, indicating the tab is marked to be stuck (true) or not (false).

Please note that this notification will be delivered when the user does something action to mark a tab to be stuck or unmarked, not when the tab is moved away from the viewport and really stuck to a tab bar edge.

This notification won't be delivered if it happens on a private window and your addon is not allowed for private windows.

See also message types to change tabs' sticky state.

When permissions for your addon are changed

This API is available on TST 3.0.12 or later.

A message with the type permissions-changed will be notified, when the requested permissions are granted/deprived, or the user allowed/disalloed to access information in private windows. Here is a list of properties the message object has:

  • grantedPermissions: An array of strings, currently granted permissions.
  • privateWindowAllowed: A boolean, indicating allowed (or not) to be notified messages from private windows.

If your addon injects additional style rules to TST's sidebar, you may need to re-inject it when permissions are changed, like:

browser.runtime.onMessageExternal.addListener((message, sender) => {
  switch (sender.id) {
    case TST_ID:
      switch (message.type) {
        ...
        case 'ready': // for restart
        case 'permissions-changed': // for permission changes
          registerToTST();
          break;
        ...
      }
      break;
  }
});

Suppress handling of new tabs by TST

This API is available on TST 3.9.6 or later.

TST handles new tabs based on their context to manage tree of tabs; e.g. attaching a tab as a child tab of the active tab when it is opened from a link in the active tab, keeping a tab independent when it is opened via the "new tab" button. The result depends on user-configured options, but TST also provides ability to override it from helper addons via its API. When TST is trying to handle a new tab, it notifies a message with the type try-handle-newtab to listener addons.

Here is a list of properties the message object has:

  • tab: A tree item corresponding to the newly opened tab.
  • activeTab: A tree item corresponding to the (old) active tab when a new tab is opened.
  • openerTab (optional); A tree item corresponding to the openerTabId of the new tab.
  • context: A string indicating the context which the tab is opened in. Please note that the value is just guessed by TST, not provided by Firefox - sometimes it maybe wrong. Possible values:
    • newtab-command: Opened by Ctrl-T, "new tab" button in Firefox's tab bar, etc.
    • with-opener: Opened from a link or script in the active tab, or opened with openerTabId attribute given by someone.
    • duplicated: Opened as a duplicated tab of an existing tab.
    • from-pinned: Opened from a pinned tab.
    • from-external: Opened by something other application, external of Firefox.
    • website-same-to-active-tab: Opened with a URL of the website same to the active tab, e.g. from a bookmark, the address bar, or something.
    • from-about-addons: AMO webpages opened from the addon manager.
    • unknown: All other cases.

If any addon responds to the message with a boolean value true, TST's handling will be canceled. For example:

browser.runtime.onMessageExternal.addListener((message, sender) => {
  switch (sender.id) {
    case TST_ID:
      switch (message.type) {
        ...
        case 'try-handle-newtab':
          if (message.context == 'newtab-command') {
            // something operation to handle new tab opened by Ctrl-T or something way.
            return Promise.resolve(true);
          }
          return;
        ...
      }
      break;
  }
});

This notification won't be delivered if it happens on a private window and your addon is not allowed for private windows.

Please note that you may also need to suppress autofixing of tree structure for moved tabs to prevent auto-attaching of the new tab by TST.

Suppress unintentional focus change by TST

This API is available on TST 3.3.7 or later.

TST automatically moves focus to the most nearest visible ancestor tab by default, when you collapse a tree and the active tab is going to be invisible. This behavior can be canceled by another addon.

  • A message with the type try-move-focus-from-collapsing-tree will be notified, when the current tab is going to be invisible by collapsing of a parent tree.
  • A message with the type try-redirect-focus-from-collaped-tab will be notified, when another tab is going to be focused for a redirection from unexpectedly focused collapsed tab. (available on TST 3.4.5 and later)

Here is a list of properties the message object has:

  • tab: A tree item corresponding to the current tab going to be invisible.
  • focusDirection (available only for try-redirect-focus-from-collaped-tab, on TST 3.4.5 and later): A number indicating the guessed focus direciton. -1 means "focus from a following tab by Ctrl-Shift-Tab", 1 means "focus from a preceding tab by Ctrl-Tab".

If any addon responds to the message with a boolean value true, TST's default behavior (activating the nearest visible ancestor tab) will be canceled. For example:

browser.runtime.onMessageExternal.addListener((message, sender) => {
  switch (sender.id) {
    case TST_ID:
      switch (message.type) {
        ...
        case 'try-move-focus-from-collapsing-tree':
          return Promise.resolve(true);
        ...
      }
      break;
  }
});

This notification won't be delivered if it happens on a private window and your addon is not allowed for private windows.

Suppress unintentional expansion of collapsed tree by TST

This API is available on TST 3.3.7 or later.

TST automatically expands existing collapsed trees by default on some situations. This behavior can be canceled by another addon.

  • A message with the type try-expand-tree-from-focused-parent will be notified, when a parent tab with collapsed children gets focused.
  • A message with the type try-expand-tree-from-focused-bundled-parent will be notified, when a parent tab with collapsed children gets pseudo focus with corresponding focused pinned tab.
  • A message with the type try-expand-tree-from-attached-child will be notified, when a child tab is attached to a collapsed tree.
  • A message with the type try-expand-tree-from-focused-collapsed-tab will be notified, when an invisible descendant tab gets focused.
  • A message with the type try-expand-tree-from-long-press-ctrl-key will be notified, when the Ctrl (Control) key is pressed for a while when you are switching tabs with Ctrl-Tab/Ctrl-Shift-Tab.
  • A message with the type try-expand-tree-from-end-tab-switch will be notified, when the Ctrl (Control) key is released after tab switching with Ctrl-Tab/Ctrl-Shift-Tab.
  • A message with the type try-expand-tree-from-expand-command will be notified when "Expand this Tree recursively" context menu (or shortcut) command is invoked. (on TST 3.9.13 and later)
  • A message with the type try-expand-tree-from-expand-all-command will be notified when "Expand All" context menu (or shortcut) command is invoked. (on TST 3.9.13 and later)

Here is a list of properties the message object has:

  • tab: A tree item corresponding to the tab trying to expand its tree. In other words, it is a parent tab.
  • child: A tree item (available only for try-expand-tree-from-attached-child, on TST 4.0 and later) corresponding to the tab attached to the parent.
  • focusDirection (available only for try-expand-tree-from-focused-collapsed-tab, on TST 3.4.5 and later): A number indicating the guessed focus direciton. -1 means "focus from a following tab by Ctrl-Shift-Tab", 1 means "focus from a preceding tab by Ctrl-Tab".
  • recursivelyExpanded (available only for try-expand-tree-from-expand-command, on TST 3.9.13 and later): A boolean indicating that the notified tab is expanded recursively. In other words, false means that the context menu (or shortcut) command "Expand this Tree recursively" is invoked on the notified tab.

If any addon responds to the message with a boolean value true, TST's default behavior (expanding the tree) will be canceled. For example:

browser.runtime.onMessageExternal.addListener((message, sender) => {
  switch (sender.id) {
    case TST_ID:
      switch (message.type) {
        ...
        case 'try-expand-tree-from-focused-parent':
        case 'try-expand-tree-from-focused-collapsed-tab':
        case 'try-expand-tree-from-long-press-ctrl-key':
        case 'try-expand-tree-from-end-tab-switch':
          return Promise.resolve(true);
        ...
      }
      break;
  }
});

These notifications won't be delivered if they happen on a private window and your addon is not allowed for private windows.

Suppress unintentional collapsion of expanded tree by TST

This API is available on TST 3.8.22 or later.

TST automatically collapses existing expanded trees by default on some situations. This behavior can be canceled by another addon.

  • A message with the type try-collapse-tree-from-other-expansion will be notified when a collapsed tree gets focused and it become expanded.
  • A message with the type try-collapse-tree-from-collapse-command will be notified when "Collapse this Tree recursively" context menu (or shortcut) command is invoked. (on TST 3.9.17 and later)
  • A message with the type try-collapse-tree-from-collapse-all-command will be notified when "Collapse All" context menu (or shortcut) command is invoked. (on TST 3.9.17 and later)

Here is a list of properties the message object has:

  • tab: A tree item corresponding to the parent tab going to be collapsed.
  • recursivelyExpanded (available only for try-collapse-tree-from-collapse-command, on TST 3.9.15 and later): A boolean indicating that the notified tab is collapsed recursively. In other words, false means that the context menu (or shortcut) command "Collapse this Tree recursively" is invoked on the notified tab.

If any addon responds to the message with a boolean value true, TST's default behavior (collapsing the tree) will be canceled. For example:

browser.runtime.onMessageExternal.addListener((message, sender) => {
  switch (sender.id) {
    case TST_ID:
      switch (message.type) {
        ...
        case 'try-collapse-tree-from-other-expansion':
          return Promise.resolve(true);
        ...
      }
      break;
  }
});

This notification won't be delivered if it happen on a private window and your addon is not allowed for private windows.

Suppress autofixing of tree structure for moved tabs

This API is available on TST 3.4.10 or later.

TST tries autofixing of tree structure when tabs are moved by other addons, but you can also deactivate the autofixing behavior fundamentally on some cases - for example your addon moves multiple tabs in a time.

A message with the type try-fixup-tree-on-tab-moved will be notified after a listener of tabs.onMoved is called, if TST tries autofixing for the moved tab. Here is a list of properties the message object has:

  • tab: A tree item corresponding to the moved tab.
  • fromIndex A number corresponding to the fromIndex of the tabs.onMoved notification.
  • toIndex A number corresponding to the toIndex of the tabs.onMoved notification.
  • action A string indicating the autofixing action. One of move, attach, detach, or moveBack (this means that TST detected the tab move as an invalid move conflicting to the current tree structure, and the tab is going to be moved back to its original position.)
  • parent: A tree item that the moved tab is going to be attached to. This will be provided when action is attach.
  • insertBefore: A tree item corresponding to a tab going to become the new next sibling tab of the moved tab. This will be provided when action is attach, detach, or move.
  • insertAfter: A tree item corresponding to a tab going to become the new previous sibling tab of the moved tab. This will be provided when action is attach, detach, or move.

If any addon responds to the message with a boolean value true, TST's autofixing will be canceled. For example:

browser.runtime.onMessageExternal.addListener((message, sender) => {
  switch (sender.id) {
    case TST_ID:
      switch (message.type) {
        ...
        case 'try-fixup-tree-on-tab-moved':
          return Promise.resolve(true);
        ...
      }
      break;
  }
});

This notifications won't be delivered if they happen on a private window and your addon is not allowed for private windows.

Suppress auto-scrolling to activated tabs

This API is available on TST 4.0.23 or later.

A message with the type try-scroll-to-activated-tab will be notified before TST tris to scroll the sidebar contents to the tab when the tab gets focus. Here is a list of properties the message object has:

If any addon responds to the message with a boolean value true, TST won't scroll the sidebar to the tab. For example:

browser.runtime.onMessageExternal.addListener((message, sender) => {
  switch (sender.id) {
    case TST_ID:
      switch (message.type) {
        ...
        case 'try-scroll-to-activated-tab':
          // Don't scroll the sidebar when the activated tab is stuck.
          if (message.type.states.includes('stuck'))
            return Promise.resolve(true);
          return;
        ...
      }
      break;
  }
});

This notifications won't be delivered if they happen on a private window and your addon is not allowed for private windows.

Suppress the "Are you sure you want to continue?" for closing multiple tabs

This API is available on TST 2.7.3 or later.

TST shows a confirmation dialog when you close multiple tabs at a time by default. If your addon already provides similar dialog and you want to suppress TST's dialog, you can do that by a grant-to-remove-tabs type message like:

browser.runtime.sendMessage(TST_ID, {
  type:  'grant-to-remove-tabs',
  tabs:  [1, 2, 3] // required, an array of tabs.Tab.id or alias
});

After that TST won't show the confirmation dialog for specified tabs.

Suppress auto-grouping of newly opened tabs

block-grouping type message disables the auto-grouping behavior for newly opened tabs.

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'block-grouping'
});

On the other hand, unblock-grouping message re-enables the auto-grouping behavior again.

let success = await browser.runtime.sendMessage(TST_ID, {
  type: 'unblock-grouping'
});

Multiple addons can block the auto-grouping behavior, so please remind that you don't forget to unblock the auto-grouping behavior before your addon is completely unloaded (disabled or uninstalled).

Manipulate bookmarks

Open bookmarks with structure

This API is available on TST 3.2.4 or later.

open-all-bookmarks-with-structure type message opens all bookmarks in the specified folder with structure. For example:

browser.runtime.sendMessage(TST_ID, {
  type:        'open-all-bookmarks-with-structure',
  id:          '4Mgbi1Guv2wi', // required, an id of a folder or a regular bookmark
  discarded:   true, // optional, keep tabs pended or not (default: user's preference)
  recursively: false, // optional, retrieve subfolders recursively or not (default: false)
});

Options discarded and recursively are available on TST 3.2.6 and later.

Please note that TST tries to open all bookmarks in its parent folder, if you specify an id of a regular bookmark.

Appendix: Index of message types

Sending message types

Notified message types

Clone this wiki locally