Safari Web Extension: How do we programmatically close the toolbar icon popup window?

After porting my Chrome extension to Safari Web Extension, I'm left with one final mystery. My toolbar icon has a popup, and that popup has an X button in the top right for the user to be able to close it. When clicked, this works on Chrome/Firefox/Edge to close it:

Code Block
window.close()


On Safari, however, I get an uncatchable warning:

Code Block
⚠️ Can't close the window since it was not opened by JavaScript.


In the old days, we had to do this on Safari:

Code Block
safari.extension.popovers[0].hide();

But that doesn't seem to be an option now. I'm assuming I need to delegate to the native app portion of the extension to close the popup, but I can't find any documentation on how to get a handle to the popup from NSExtensionRequestHandling. I can get a message to it using the nativeMessaging permissions and:
Code Block
browser.runtime.sendNativeMessage("ignored", {
message: "CLOSE_POPUP"
})

...but once in the native app handler, I'm not sure what to do next. Any ideas?



window.close from the extension's popup is expected to work.

Can you please file a bug report using https://feedbackassistant.apple.com and include a sample extension that reproduces this? I've written a test extension and window.close works correctly from there in my testing.

Thanks!
hey bweinstein,

is it expected to work in options as well?

i have the following workflow:
  1. upon install, open onboarding in options

  2. after onboarding, prompt for user to login

  3. once logged in, display "success" confirmation and window.close() in 10 seconds.

getting the same error:

⚠️ Can't close the window since it was not opened by JavaScript.


I had the same issue.

According to MDN documentation:

This method can only be called on windows that were opened by a script using the Window.open() method. If the window was > not opened by a script, an error similar to this one appears in the console: Scripts may not close windows that were not
opened by script.

Note also that close() has no effect when called on Window objects returned by HTMLIFrameElement.contentWindow.

There's one workaround which sometimes works and sometimes not:
Code Block javascript
const closePopup = () => {
window.open('', '_parent', '');
window.close();
};


You can try if it works in your case.

P.S.
We decided to hide a close button in case if it's a Safari extension. Users can click on the extension icon or outside of the extension popup to close it.

@bweinsten Could you provide the code to your test extension? I will make a barebones extension to test myself, but it could expedite things if I could see yours working. To be clear though, this is the popover that appears when the user clicks the icon in the toolbar, not a window that is opened using window.open().

@vkyrychenko87 No luck. Seems Safari is the only browser conforming to the MDN docs, OR the other browsers use a script behind the scenes to open the window and Safari does not. Either way, Safari is the outlier. In addition to my X button, though, I also have the need the programatically close the popover when the user clicks a link in it to navigate on the current tab. In instances where a new tab is opened, the popover goes away automatically, but if a link opens in the current tab, the popover just hangs around, obscuring the view. So my close method has two use cases: 1) Manually click the X button to close, and 2) Automatically close when a link is clicked in the popover.

There has to be a way to do this, even if it's delegating to the native swift handler. Real head scratcher that it's non-obvious.

I found a workaround. When you want to close your popup from within the popup, do this:

browser.runtime.reload();

Weird, right? It closes as a side effect of reloading the popover. Super hacky but keeps me moving while Apple fixes the underlying issue or otherwise gives us a way to close it.

In my test case, I have:

  document.getElementById("closeMe").addEventListener("click", function() { window.close(); });

Where "closeMe" is a button. Clicking the button dismisses the popover. If that's not what you're seeing, can you please file some feedback at https://feedbackassistant.apple.com with a sample project that reproduces this?

Thanks!

@climb An options page provided by your extension has access to all of the same web extension APIs as a popover and the background page, so you could probably use the tabs API to close a tab after the login flow completes.

I found that if I navigate using history.push() within the popup, then window.close() will not work. Using history.replace() instead will still allow javascript to close the popup.

I.e. history.length couldn't be greater than 1.

That seems to fit with this:

https://github.com/WebKit/WebKit/blob/3644f1bb237c11a5e51754fd4a56b041d247ecb6/Source/WebCore/page/DOMWindow.cpp#L1044

(Thanks: https://textslashplain.com/2021/02/04/window-close-restrictions/)

Safari Web Extension: How do we programmatically close the toolbar icon popup window?
 
 
Q