# Configurable browser action for MV3 extension

**URL:** <https://discourse.mozilla.org/t/configurable-browser-action-for-mv3-extension/133603>\
**Category:** Development\
**Created:** [July 15, 2024, 6:31am UTC](https://discourse.mozilla.org/t/configurable-browser-action-for-mv3-extension/133603 "2024-07-15T06:31:08Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![aecreations](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/aecreations/32/30593_2.png) [@aecreations](https://discourse.mozilla.org/u/aecreations)\
**Post date:** [July 15, 2024, 6:31am UTC](https://discourse.mozilla.org/t/configurable-browser-action-for-mv3-extension/133603/1 "2024-07-15T06:31:08Z")

</div>

I’m trying to make the browser action in my Firefox MV3 extension configurable so that the user can choose to either open an extension page in a popup window or show a sidebar UI. The configuration would be set in the extension preferences page, and the setting stored in extension storage (get/set via the `browser.storage.local` API).

But I’m running into a blocker due to [`browser.sidebarAction.open()` only callable from a user action](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/sidebarAction/open). In the browser action handler, I would need to read the user’s preference from storage to determine whether to open the sidebar or the popup window. But the following doesn’t work:

```
browser.action.onClicked.addListener(async (aTab) => {
  // Get the user's preferred action when the browser action is clicked
  let pref = await browser.storage.local.get("browserAction");
  if (pref.browserAction == 1) {
    // This doesn't work!
    browser.sidebarAction.open();
  }
  else {
    openThePopupWindow();
  }
});

```

And from what I understand, it doesn’t work because putting `browser.sidebarAction.open()` inside an async function [causes it to lose the user action/input context](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/User_actions). But it’s necessary because the `browser.storage` APIs are asynchronous.

What workarounds should I consider?

---

<div class="post-metadata">

**Author:** ![juraj.masiar](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/juraj.masiar/32/30587_2.png) [@juraj.masiar](https://discourse.mozilla.org/u/juraj.masiar)\
**Post date:** [July 15, 2024, 9:15am UTC](https://discourse.mozilla.org/t/configurable-browser-action-for-mv3-extension/133603/2 "2024-07-15T09:15:58Z")

</div>

There is a plan to remove the user-action requirement for the similar “openPopup” API:

> **[1799344 - Remove \`extensions.openPopupWithoutUserGesture.enabled\` preference](https://bugzilla.mozilla.org/show_bug.cgi?id=1799344)**
>
> NEW (nobody) in WebExtensions - General. Last updated 2024-06-05.

I think the same reasoning could be used for the sidebar.  
Especially when using non-persistent background scripts where you can’t access async store to read user preferences when the script just woke up.

The only workaround I can think of is to use “localStorage”, which is synchronous. But this will work only in Firefox since Chromium service workers can’t access localStorage anymore.

---

<div class="post-metadata">

**Author:** ![ComputerWhiz](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/computerwhiz/32/20011_2.png) [@ComputerWhiz](https://discourse.mozilla.org/u/ComputerWhiz)\
**Post date:** [July 15, 2024, 1:37pm UTC](https://discourse.mozilla.org/t/configurable-browser-action-for-mv3-extension/133603/3 "2024-07-15T13:37:35Z")

</div>

The solution I’ve used in the past is to use the [storage.onChanged API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/onChanged) to listen for changes to the settings. Then you can change the browserAction.onClicked listener as needed by removing the old one and putting in the new one.

It’s potentially slightly more performant because you are handling the user’s setting before it’s needed, so you no longer need to waste time loading the setting when the user clicks.

---

<div class="post-metadata">

**Author:** ![aecreations](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/aecreations/32/30593_2.png) [@aecreations](https://discourse.mozilla.org/u/aecreations)\
**Post date:** [July 16, 2024, 7:23am UTC](https://discourse.mozilla.org/t/configurable-browser-action-for-mv3-extension/133603/4 "2024-07-16T07:23:13Z")

</div>

Thanks @juraj.masiar - the solution is exactly what I needed! I’m not too concerned about incompatibility with Chrome since the extension is only intended to work in Firefox.

@ComputerWhiz This is what I would have done in the past as well, but my extension is MV3, and I found that when the suspended background script is restarted when the browser action is clicked, repopulating the setting in the background page won’t happen in time for the `browser.action.onClicked` listener to read it.

---

<div class="post-metadata">

**Author:** ![dotproto](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/dotproto/32/62957_2.png) [@dotproto](https://discourse.mozilla.org/u/dotproto)\
**Post date:** [July 19, 2024, 11:47pm UTC](https://discourse.mozilla.org/t/configurable-browser-action-for-mv3-extension/133603/5 "2024-07-19T23:47:12Z")

</div>

Building on what @juraj.masiar shared, [there are also plans](https://bugzilla.mozilla.org/show_bug.cgi?id=1800401#c5) to remove the user interaction requirement from other similar UI surfaces like the pageAction and sidebarAction APIs.

That said, I still think we have a broader problem with reacting to user actions asynchronously in background event listeners. For example, say you use the `action.onClicked` event to trigger a `permissions.request()` call, but first you need to fetch a value from storage in order to make the correct permission request. While I can’t promise any specific action, it’s at least a problem that we’re aware of.
