Search code examples
javascriptcssfirefox-addon-webextensionsshadow-domweb-extension

CSS hover and cursor don't work in shadow DOM


I'm working on a browser addon that inserts a widget into any website as a shadow DOM, but for some reason I'm unable to make the CSS :hover selector and cursor property working.

Here's the snippet of the content script that creates the shadow DOM:

var inpagePopupHTML = "";
var insertStylesHTML = "";

// load the widget HTML from a resource file (works fine)
$.get(browser.runtime.getURL("/ui/mistake-popup.html"), function(data) {
  inpagePopupHTML = data;
});

// load the style for the widget from an HTML file that only contains <style>...</style> (works fine)
$.get(browser.runtime.getURL("/css/insert-styles.html"), function(data) {
  insertStylesHTML = data;
  document.body.innerHTML += data; // the CSS file is inserted here because it also contains styles for the whole page, not just the inserted widget
});

$("body").append('<div class="grammle--shadow" style="all: initial;"></div>'); // "all: initial" prevents the shadow DOM from inheriting styles
var shadow = document.querySelector(".grammle--shadow").attachShadow({ mode: "open" });
shadow.innerHTML += inpagePopupHTML;
shadow.innerHTML += insertStylesHTML; // the same CSS file is also put into the shadow DOM since it contains styles for the inserted widget

Here's the content of mistake-popup.html:

<div class="grammle--popup grammle--popup--minimised">
  <div class="grammle--popup-text">
    <span class="grammle--popup-text-counter">0</span>
    <span class="grammle--popup-text-label">Fehler</span>
  </div>

  <div class="grammle--popup-icons">
    <span class="grammle--popup-icon" part="icon">
      <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-up" viewBox="0 0 16 16">
        <path fill-rule="evenodd" d="M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708l6-6z"/>
      </svg>
    </span>

    <span class="grammle--popup-icon" part="icon">
      <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x-lg" viewBox="0 0 16 16">
        <path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854Z"/>
      </svg>
    </span>
  </div>
</div>

Here's insert-styles.html:

<style>
:root {
    --grammle-dark-main-colour: #137768;
    --grammle-dark-main-colour-hover: #0f6a5d;
}
...

.grammle--popup-icon {
  cursor: pointer;
  padding: 4px;
  background-color: var(--grammle-dark-main-colour);
  border-radius: 3px;
}

.grammle--popup-icon:hover {
  background-color: var(--grammle-dark-main-colour-hover);
}

...
</style>

Here's a preview of the green widget being correctly inserted and displayed in the right bottom corner on https://keyoxide.org/hkp/[email protected], just as intended:

As you can see, the “static style” of the widget is correctly applied (so it's not a problem of the CSS not being inserted, for example), but when moving the cursor over either of the icon buttons, neither the darker background colour nor the pointer cursor are applied.

Why is that and how to fix it?

Thanks for your help!


Solution

  • I found a work-around myself: Instead of adding the CSS styles in-line, I added a <head> element to the shadow DOM:

    var shadowHead = document.createElement("head");
    $(shadowHead).append('<link rel="stylesheet" href="' + browser.runtime.getURL("/css/insert-styles.css") + '" type="text/css" />');
    $(shadow).prepend(shadowHead);
    

    I don't know why, but this works now.