Hello. First post here, so please let me know if I’m in the wrong place.
Near the bottom of the Keyboard shortcuts page, there is a short section entitled “Selection of Multiple Tabs”, which describes a few shortcuts which can be used while the tab bar has focus, but says the only way to give the tab bar focus is to give the address bar focus and then to use Shift-Tab repeatedly until the tab bar becomes focused.
That page is user-oriented, so I’m thinking the term “only way to do this” is from a user perspective. My question is: is there a programmatic way that an extension can use to give the tab bar focus, and then proceed to manipulate tabs as described for those shortcuts?
Nope. Currently an extension’s ability to manage focus in Firefox is limited to switching focus between windows (using windows.update()) and selecting an active tab (using tabs.update()).
The WebExtensions Community Group (WECG) has talked a bit about focus management in extensions. This discussion started in response to a request from developers to be able to change focus between an extension’s sidebar page and the main document in a tab. While we’ve touched on the idea of broader focus management capabilities, so far my impression is that browser vendors are very hesitant about allowing extensions to do things like focus the address bar.
Getting back to your question, if you just want to set the currently selected tabs, you can do that with either tabs.highlight(). Note that this DOES NOT focus the tab strip. tabs.update() can also be used to similar effect, but it’s a little more fiddly to work with for this use case.
I think for this specific case (giving focus to the tabs bar), it would be much better to simply request a new keyboard shortcut directly from Firefox on Bugzilla.
Similarly how one can use Ctrl + K or Ctrl + L to focus Search / URL.
I have to say, I’ve never this feature, but it’s actually pretty cool.
Thanks to both for your helpful replies. If a new shortcut were made available (like Ctrl+K or Ctrl+L) would it then be accessible from extensions?
When one uses the technique mentioned in the article, he can then use the keyboard to navigate the tabs, but with the restriction that every move to a new tab causes that new tab to become the active tab. This is unlike using the mouse to multi-select tabs with Shift or Control.
My goal was to create an extension that allows the user to use the keyboard to navigate the tabs, multi-focusing individual tabs with the space bar (like Ctrl-click with the mouse) or a group of tabs with another key (like Shift-click with the mouse). So far, I’ve thought of using tabs.highlight() (as mentioned) to focus tabs while stepping through the tabbar, which gives each multi-selected tab a border (just like with the mouse). [I hadn’t thought of tabs.update() for that; would that in some way be better?]
The next problem, though, is that there is no way for the user to visually identify which tab is the current tab (not which is the active tab, nor which tabs are multi-selected, both of which are visible, but which tab is current in navigating the tab strip). There seems to be no way for an extension to modify the tab strip, such as giving the current tab a different border, or colour, or font, etc. One can modify the title to, for example, place a coloured dot at the beginning of the current tab. But this requires an injected script, and so won’t work on restricted pages.
And I’m sure there will be other difficulties as well. But any thoughts as to the feasibility or implementation of such an extension would be welcome.
I was just about to say “let’s take a step back, what are you trying to accomplish?” Turns out you beat me to it, @mr.qwerky. Thanks
I want to clarify some terminology real quick to make sure we’re all on the same page.
What you descried as “multi-focusing … a group of tabs” is referred to in the Tabs API as having multiple highlighted tabs. The active tab is also highlighted and cannot be unhighlighted.
The phrase “group of tabs” would generally refer to a tab group.
“Focus” isn’t a concept that’s exposed on the Tabs API (that’s arguably one of the problems for your use case), but the tab that currently has focus (is visible) in a window is referred to as the active tab. Each window can only have one active tab at a time.
Okay, with that out of the way, let’s get back to it.
You can definitely build an extension that allows users to select (highlight) tabs and perform actions on the current set of selected tabs. That being said, I don’t think there’s a good way to implement the Ctrl-Click style behavior that you described. The core problem here is that browsers don’t expose a way for extensions to manage what tab is focused in the tab strip.
The Shift-Click style behavior is more straightforward because you can side-step the concept of selecting/focusing a tab without highlighting it. For example, you could have a set of keyboard shortcuts to grow/shrink the current set of highlighted tabs. You could also implement some shortcuts to reposition your current highlighted tabs in the tab strip (move to start, move to end, move one over, etc.).
While you can’t manage focus in the tab strip, you can always implement your own UI. It’s not ideal, but one approach would be to open a temporary popup window that allows users to interact with a virtual tab strip and stage a set of actions. Once the user commits the action, the popup closes and the extension applies the modifications to the browser. This would allow you to implement your own focus management system and select an arbitrary set of tabs in the current window or even across windows.
There isn’t an explicit API to style or decorate a given tab, but Firefox’s Theme API can be used to dynamically update the browser’s theme. You can find the current set of theme-able properties in the "theme" manifest key docs. The main way I can see you using this API in your extension is to change the theming of highlighted tabs (the tab_selected key in the theme object) when the user uses your extension to interact with highlighted tabs. That said, be aware that theme updates can be a little laggy.
Themes don’t allow for arbitrary styling of tabs with CSS, so you can’t create a CSS selector that matches the Nth tab in the tab strip. Unfortunately, that means this API can’t be used to implement your own tab selection logic.
Thanks for a great reply. Sorry about the incorrect terminology–yes, I did indeed mean multi-select, but must have had a brain-cramp and wrote focus , and yes I was referring to using the highlighting API. It never occurred to me that “group of tabs” might be taken as a tab group. I know tab groups are brand new (again!) to Firefox, but I’ve been using Simple Tab Groups so long that that new feature didn’t even enter my mind. And yes, I know the window’s current tab is the “active” tab, but I was trying to indicate the tab which would be current as the user moves along the tab strip (which may or may not be multi-highlighted), rather than the active tab.
You are 100% correct that there seems to be no way for an extension to reliably indicate which tab is that “focused/selected” tab, and this is one of the immediate problems that I am running up against. One possible way would be to change the tab title (such as placing a coloured dot in front of it), but this won’t work on restricted pages. Using the Theme API never occurred to me, as I’ve never really used themes. Would that API allow one tab to be distinguished from all the others? Oh, I think you already indicated that the answer is no.
For Ctrl-click style behaviour, one would need to keep an updated array of all tabs currently highlighted; I think that should be doable. In that way, using the highlight API, individual tabs should be able to be selected/highlighted without becoming active, just like Ctrl-click.
Implementing an additional UI was also suggested to me by another source (ChatGPT ), but I would prefer to stick with the existing one. The scenario that I had in mind so far, is to use a pop-up that would be invisible (height/width=0). The extension’s icon would change colour when the pop-up was opened by either a hotkey or by clicking the icon. While open, popup.js would listen for ‘keydown’ to move the current/selected/focused tab with up/down/left/right/pgup/pgdn/home/end, and spacebar to toggle the highlight of the current tab, or perhaps Shift-space to select the group of tabs ranging from the anchor tab (the active tab) to the current tab; or Enter to simply activate the current tab. Escape would close the pop-up and restore the icon colour. And yes, I did plan on code to allow the highlighted tabs to be moved as well.
Thus far I’ve come, but would certainly welcome any suggestions or ideas.
You can definitely maintain your own list of highlighted tabs, but you and the browser may get out of sync. If you can, it might be easier to defer to the browser. Here are two alternative that don’t require you to maintain your own list of highlighted tabs.
In the first approach, we ask the browser to provide the current set of highlighted tabs, we tweak it, and then we use tabs.highlight() apply our new set of highlights.
async function addHighlightById(tabId) {
const [newTab, highlighted] = await Promise.all([
browser.tabs.get(tabId),
browser.tabs.query({ lastFocusedWindow: true, highlighted: true }),
]);
// Ensure the active tab the first entry in the array, otherwise the active
// tab will change when we call `tabs.highlight()`
const active = highlighted.splice(highlighted.findIndex(t => t.active), 1);
const newHighlights = [...active, ...highlighted, newTab].map(t => t.index);
await browser.tabs.highlight({ tabs: newHighlights });
}
addHighlightById(TAB_ID);
The second approach is even more direct. Rather than try to give the browser a complete list of tabs to highlight, we just ask the browser to add a specific tab to the set of highlighted tabs by calling tabs.update().
For operations like adding or removing a single tab, I prefer the second approach because it minimizes the chances that I’ll make a mistake or forget about an edge case. Ultimately, though, the best solution is the one that works best for you.
So it seems to be a brick wall. Scenario: Firefox has just been restarted, and all the tabs are there from the previous session, one can see their favicons and titles, but none are loaded except the current active tab. In this state, it seems one can’t use content.js or script injection to change a non-active tab’s title, because its content is not yet loaded–correct?
If that is so, then there is simply no way that I’m aware of to visually indicate in the browser UI, which tab is currently focused (not the active tab, but focused as in tab navigation), as opposed to all the other tabs. Without that, the idea is dead.
So, is there any other possible way? I’m already using userChrome.css to style tabs, so all that would be needed is some way within the browser UI to give a specific tab some new attribute that could be styled in userChrome.css. How about userChrome.js? I’ve not used that, and don’t know if it could do that or not. And even it it could, would there be some way that the userChrome.js script and the extension could communicate with one another?
Unfortunately all I know about userChrome.js is that it exists. I’ve never tried hacking around with it myself. Hopefully someone else will be able to jump in.
Using Firefox 128 ESR, is it still possible to use webextension-experiments? In about:config I have:
extensions.experiments.enabled = true
xpinstall.signatures.required = false
Then I have a very simple test extension (webextension-experiment), which even when loading manually fails with the load-time web console error:
[ACTION FAILED] TEMPORARY_EXTENSION_INSTALL_FAILURE: Add-on custom-tab-styler@example.com is not compatible with application version. add-on minVersion: 63.0.
Have tried many permutations of strict_min_version and strict_max_version without any change in the results. The only thing that gets past that error, is to remove the permission "experiments.customTabStyler", which results in the inspection console error: InvalidStateError: An exception was thrown at runtime rather than at load-time. I am out of my depth here.
I’m not sure what’s going on with that error message, but you shouldn’t need to set strict_min_version or strict_max_version because you can’t distribute experimental extensions on AMO.
Have you tested in Firefox Nightly or Developer Edition? This documentation suggests that only those versions are supported and, while I’m not familiar with Firefox’s build process, what I’m seeing in build config files seems to confirm that.