Problem with MenuManager registered context submenus

31 views
Skip to first unread message

Kris De Meyer

unread,
Feb 13, 2026, 8:19:43 AM (5 days ago) Feb 13
to zotero-dev
I'm working on a plugin under Zotero 8 - latest dev beta - on Windows 10.

When trying to use the new MenuManager API to create a "main/library/item" and "main/library/collection" submenu with menuitems, the submenu item appears in the context menu, but it doesn't have a popup menu associated with it - meaning that hovering over it doesn't do anything.

I reproduced the same behaviour in zotero-better-notes - very latest version - which has already moved its menu management to the new MenuManager API. The repo doesn't use a context menu, so hasn't yet shown up the bug, but I added some code to its menu.ts file registering all it its menus and the bug appears there too.

The code that I used to register the submenu with child menuitems is this:

```js
Zotero.MenuManager.registerMenu({
menuID: `${config.addonRef}-bugrepro-library-item`,
pluginID: config.addonID,
target: "main/library/item",
menus: [
// Hidden diagnostic item
{
menuType: "menuitem",
l10nID: `${config.addonRef}-bugrepro-diag`,
onCommand() {},
},

// The submenu under test
{
menuType: "submenu",
l10nID: `${config.addonRef}-bugrepro-submenu`,
icon: `chrome://${config.addonRef}/content/icons/favicon.png`,
menus: [
{
menuType: "menuitem",
l10nID: `${config.addonRef}-bugrepro-child1`,
onCommand() {
Zotero.debug("[MenuManager bug repro] child1 clicked");
},
},
{
menuType: "menuitem",
l10nID: `${config.addonRef}-bugrepro-child2`,
onCommand() {
Zotero.debug("[MenuManager bug repro] child2 clicked");
},
},
],
},
],
});
```
This is the resulting DOM tree:

< menu xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" class="zotero-custom-menu-item zotero-custom-menu-L0kxC1JG-1770913655563 menu-iconic" data-l10n-id="BetterNotes-bugrepro-submenu" style="--custom-menu-icon-light: url(chrome://BetterNotes/content/icons/favicon.png); --custom-menu-icon-dark: url(chrome://BetterNotes/content/icons/favicon.png);" data-dynamic-classes="">MenuManager Submenu< /menu>

For other context submenus from other plugins not created with MenuManager (zotero-better-bibtex, for example), the submenu has a < menupopup> element in the DOM.

There are no errors triggered anywhere - the only diagnostic I found is that the < menupopup> element is missing in the DOM. I tried a number of things to get more information - including inserting an 'onShowing' function in the submenu that would throw an error message with more context information, but it never gets triggered, indicating it probably doesn't get created or gets stripped out too.

I've been digging into this with an AI agent to double-check that I was doing things correctly. After trying a number of things, this is its summary of the diagnosis.

Specifically: _initMenu() is not appending a < menupopup> in the submenu case, despite the code path. But we see it created as < menu> not < menuitem>, and it has the menu-iconic class that MenuManager adds for submenus with icons — so it knows it’s a submenu. So the creation switch is being hit, but the < menupopup> is missing afterwards. That strongly implies: The < menupopup> is created and appended, then later removed/dropped

Likely due to:
- node being moved/cloned by some other part of Zotero’s context menu code after MenuManager appends it
- XUL menu sanitization that strips menupopup children on customnodes in that specific popup
- a CSS/markup mismatch causing the popup not to be retained

The key: you have anode surviving but missing its popup child — that’s consistent with “child got dropped during reparenting”.

Any thoughts what's happening?

Best,

Kris

XY Wong

unread,
Feb 13, 2026, 8:38:36 AM (5 days ago) Feb 13
to zotero-dev
Just checked Windows & Linux & MacOS and all of them work perfectly fine with your code. Please stop sending AI generated nonsense stuff.

Xiangyu Wang

unread,
Feb 13, 2026, 8:51:05 AM (5 days ago) Feb 13
to zoter...@googlegroups.com
Please describe the issue with eg. screenshot so that we can help.

I would very much suspect that it’s just the locale string you used are not added to the corresponding ftl file.

--
You received this message because you are subscribed to the Google Groups "zotero-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to zotero-dev+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/zotero-dev/d91f0080-5205-4d8f-b368-3fc6dc0fa12cn%40googlegroups.com.

Kris De Meyer

unread,
Feb 13, 2026, 12:12:55 PM (5 days ago) Feb 13
to zotero-dev
Thanks, Xiangyu.

Here's the screenshot:
Zotero Screenshot.png

The submenu is created, but there's no popup attached to it, so hovering over the submenu does nothing.

Here's the screenshot from the relevant part of the Inspector window - there's no <menupopup> element where you'd expect one.

Zotero Screenshot 2.png

I don't think it's simply a locale problem, because the submenu item has the correct string label ("MenuManager Submenu") that I put in the relevant locale file. 

Even if there was a missing locale string, one wouldn't expect that this would lead to the popup menu not being created without it generating an error or warning.

Here's the code that I used to register the menus:

// --- MenuManager submenu repro (item context only) ---
  Zotero.MenuManager.registerMenu({
    menuID: `${config.addonRef}-bugrepro-library-item`,
    pluginID: config.addonID,
    target: "main/library/item",
    menus: [
      // The submenu under test
      {
        menuType: "submenu",
        l10nID: `${config.addonRef}-bugrepro-submenu`,
        icon: `chrome://${config.addonRef}/content/icons/favicon.png`,
        menus: [
          {
            menuType: "menuitem",
            l10nID: `${config.addonRef}-bugrepro-child1`,
            onCommand() {
              Zotero.debug("[MenuManager bug repro] child1 clicked");
            },
          },
          {
            menuType: "menuitem",
            l10nID: `${config.addonRef}-bugrepro-child2`,
            onCommand() {
              Zotero.debug("[MenuManager bug repro] child2 clicked");
            },
          },
        ],
      },
    ],
  });


Here are the locale strings from the relevant .ftl file in the build folder:

BetterNotes-bugrepro-submenu = MenuManager Submenu
BetterNotes-bugrepro-child1 = Child 1
BetterNotes-bugrepro-child2 = Child 2

As is visible in the screenshot above, the submenu locale string is found - so it would be strange if the Child 1 and Child 2 strings cannot be found and cause the popup menu to disappear.

My Zotero installation is 8.0.2-beta.5+c35d7f21e (64-bit) on Windows. I've used zotero-better-notes v3.0.2 to add my registerMenu calls to menu.ts and my l10nID labels to its mainWindow.ftl file.

If there's any other information I need to provide, please let me know.

XY Wong

unread,
Feb 13, 2026, 1:12:34 PM (5 days ago) Feb 13
to zotero-dev
It's the FTL string issue.

You are using the terms like bugrepro-submenu = MenuManager Submenu`, which means it will replace the whole innerHTML of the `<menu/>` element once FTL is compiled. That's also why you didn't see the `<menupopup/>` inside it.

You should use 

```
bugrepro-submenu =
    .label = MenuManager Submenu
```

instead. Since you are working on the Better Notes plugin, please check other strings as examples in the locale folder.

Kris De Meyer

unread,
Feb 14, 2026, 1:51:25 AM (4 days ago) Feb 14
to zotero-dev
OK, thanks, that fixes the problem indeed. 

I don't/didn't know Fluent, so this issue caught me out, especially because it doesn't happen when using the same locale strings with zotero-plugin-toolkit's MenuManager. 

In other words, porting code from the plugin toolkit's MenuManager to Zotero's new MenuManager without changing the format of the locale strings will surface this issue.

If this is intended/unavoidable behaviour from Fluent, then would it be possible to add a warning to this page to alert people to the format of the Fluent strings they have to use - because it's not clear from anything right now. Even looking at Fluent's syntax description doesn't immediately make it clear that forgetting to use the .label attribute causes an entire popup menu to be replaced by a string.

Best,

Kris

Reply all
Reply to author
Forward
0 new messages