Search code examples
google-chromegoogle-chrome-extension

How to disable (gray out) page action for Chrome extension?


I want the Chrome extension icon to be disabled (grayed out) on all pages except for pages on docs.google.com. This is my code in background.js.

'use strict';

chrome.runtime.onInstalled.addListener(function() {
  chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
    chrome.declarativeContent.onPageChanged.addRules([{
      conditions: [new chrome.declarativeContent.PageStateMatcher({
        pageUrl: { urlContains: 'docs.google' },
      })
      ],
          actions: [new chrome.declarativeContent.ShowPageAction()]
    }]);
  });
});

From the documentation for pageActions this should result in my extension icon being gray on all pages except for ones that have docs.google in the URL. But the icon is active (NOT grayed out) on all pages. Tapping it on non docs.google pages results in it not doing anything, but I want it to be grayed out in the first place.

Any ideas on this?


Solution

  • This is a bug in Chrome and so far it's unclear if it's even fixable.

    Meanwhile, you can maintain the icon yourself:

    1. make a grayscale version of the icon(s) in any image editor and save them separately.

    2. specify the gray icon in manifest.json:

      • ManifestV2:

        "page_action": {
          "default_icon": { "16": "icons/16-gray.png", "32": "icons/32-gray.png" }
        }
        
      • ManifestV3 uses action instead of page_action

        "action": {
          "default_icon": { "16": "icons/16-gray.png", "32": "icons/32-gray.png" }
        }
        
    3. set the normal icon using SetIcon action:

      chrome.declarativeContent.onPageChanged.removeRules(async () => {
        chrome.declarativeContent.onPageChanged.addRules([{
          conditions: [
            new chrome.declarativeContent.PageStateMatcher({
              pageUrl: { hostPrefix: 'docs.google.' },
            }),
          ],
          actions: [
            new chrome.declarativeContent.SetIcon({
              imageData: {
                16: await loadImageData('icons/16.png'),
                32: await loadImageData('icons/32.png'),
              },
            }),
            chrome.declarativeContent.ShowAction
              ? new chrome.declarativeContent.ShowAction()
              : new chrome.declarativeContent.ShowPageAction(),
          ],
        }]);
      });
      
      // SVG icons aren't supported yet
      async function loadImageData(url) {
        const img = await createImageBitmap(await (await fetch(url)).blob());
        const {width: w, height: h} = img;
        const canvas = new OffscreenCanvas(w, h);
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0, w, h);
        return ctx.getImageData(0, 0, w, h);
      }