Search code examples
google-chrome-extensionchrome-extension-manifest-v3

Chrome Extension with no HTML to directly run JS (display alert with DOM value) after clicking its icon


I couldn't find any ready-made solutions, especially with the new Manifest V3 background service-worker architecture.

I need to create a simple Chrome Extension with no HTML to directly run JS to show an Alert Box with some kind of DOM value (e.g., a DIV's ID) when its icon is clicked. But I'm getting these errors:

manifest.json

{
  "manifest_version": 3,
  "name": "Practice",
  "description": "Practice",
  "version": "1.0",
  "action": {
    "default_icon": "practice.png"
  },
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["practice.js"],
    "run_at": "document_end"
  }]
}

background.js

chrome.tabs.onUpdated.addListener(function () {
  chrome.tabs.executeScript(null, { file: "practice.js" });
});

practice.js

var elem = document.getElementById("myDiv");
alert(elem ? 'found: ' + elem.id : 'not found');

ERROR in background.js:

Uncaught ReferenceError: alert is not defined

Solution

    1. The code you've shown won't even run because there's no chrome.tabs.executeScript in ManifestV3, it's chrome.scripting.executeScript and the syntax is completely different. Also you need either host_permissions (for unattended/automatic injection) or activeTab permission (injection on click).
    2. chrome.tabs.onUpdated is the wrong event, you need chrome.action.onClicked, but in this specific case a better/simpler alternative is to specify "default_popup" in manifest.json and remove the background script.
    3. There's no need for content_scripts declaration because it injects the specified scripts into each page in each tab every time it's navigated and not on click.

    // manifest.json

    {
      "manifest_version": 3,
      "name": "Practice",
      "description": "Practice",
      "version": "1.0",
      "action": {
        "default_popup": "popup.html",
        "default_icon": "practice.png"
      },
      "permissions": ["activeTab", "scripting"]
    }
    

    popup.html

    <p id=msg></p>
    <script src=popup.js></script>
    

    popup.js

    (async () => {
      const [tab] = await chrome.tabs.query({active: true, currentWindow: true});
      const [{result, err}] = await chrome.scripting.executeScript({
        target: {tabId: tab.id},
        injectImmediately: true,
        func: id => document.getElementById(id)?.id, // result must be JSON-compatible
        args: ['myDiv'],
      }).catch(err => [{err: err.message}]);
      document.getElementById('msg').textContent = result
        ? 'found: ' + result
        : err || 'not found';
    })();