Search code examples
javascriptgoogle-chrome-extension

Issue with Google Chrome chrome.sidePanel API


I am developing a simple extension that will allow users to select a text from a web page and then right click on it, choose an item from the contextual menu and see a definition for that word. When doing this I want to open the Chrome side panel only for that specific tab.

I wrote the following in the service-worker.js

function setupContextMenu() {
  chrome.contextMenus.create({
    id: 'define-word',
    title: 'Define',
    contexts: ['selection']
  });
}

chrome.runtime.onInstalled.addListener(() => {
  setupContextMenu();
});

chrome.contextMenus.onClicked.addListener((data) => {

  chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
          if (tabs.length > 0) {
            const tabId = tabs[0].id;
            chrome.sidePanel.open({ tabId });
          }
        });

        chrome.runtime.sendMessage({
                name: 'define-word',
                data: { value: data.selectionText }
              })


});

The problem is that the side panel is opened but the definition is not displayed so, once opened I have to select again the term to see the definition displayed. I think it's a problem of timing, probably the selected text is sent before the side panel is opened so I don't see it... do you have an idea on how I could fix it and make so that the side panel is opened and then the definition is displayed? Thanks for helping!

Giaco


Solution

  • When you send the message the side panel hasn't yet opened, so it can't receive the message.

    Instead you can set the text as a path parameter:

    // background script
    chrome.contextMenus.onClicked.addListener(async (data, tab) => {
      const text = data.selectionText;
      const tabId = tab.id;
      const path = chrome.runtime.getManifest().side_panel.default_path
        + '?' + new URLSearchParams({text});
      await chrome.sidePanel.setOptions({tabId, path});
      await chrome.sidePanel.open({tabId});
    });
    
    // panel script
    const selectedText = new URLSearchParams(location.search).get('text');
    

    Another solution is to store the text in chrome.storage.session in the background script and read it at the beginning of the side panel script.

    Yet another solution is to reverse the direction of communication, so that the side panel asks for the text via chrome.runtime.sendMessage and the background script sends it in chrome.runtime.onMessage.