Web Components Community 🔷

Cover image for Tiny trick - :where() for easily overridden default CSS
Cameron
Cameron

Posted on

Tiny trick - :where() for easily overridden default CSS

I recently had a lightDOM webcomponent and I wanted to supply default CSS but make sure it would be easy to override.

The quickest way to add some default styling without a shadowroot was just to insert a <style> element in as part of the element.

this.insertAdjacentHTML('beforebegin',/*html*/`<style>a-box {display:block;outline:3px dashed grey;} a-box.over {outline: 3px dashed green;}</style>`);
Enter fullscreen mode Exit fullscreen mode

Since this goes into the global stylesheet, if the user tries to add their own CSS above the location of the <a-box> element then their CSS is overridden by the defaults.

Luckily I recently read something about the :where pseudo-selector and noticed that it has the side-effect of nullifying the specificity of a selector.

So :where(a-box) {...} behaves like a-box {...} but has a lower specificity, so an a-box CSS rule provided by the user will override the default CSS even if it occurs before the a-box.

Example showing earlier CSS overriding defaults

<!DOCTYPE html>
<html>
  <head>
    <style>
      a-box {
        outline:3px solid orange;
        width:5em;
      }
    </style>
  </head>
<body>
  <script>
    class Box extends HTMLElement {
      async connectedCallback() {
        this.insertAdjacentHTML('beforebegin',/*html*/`<style>:where(a-box) {display:block;outline:3px dashed grey;} a-box.over {outline: 3px dashed green;}</style>`);
      }
    }
    window.customElements.define("a-box", Box);
  </script>

  <a-box>
    Stuff in a box
  </a-box>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

A screenshot showing the a-box element with an orange outline as per the user-supplied CSS

I can't think of any downsides, but there might be a better way to manage CSS for lightDOM components of which I'm not aware.

Top comments (3)

Collapse
auroratide profile image
Timothy Foster

Neat trick!

For a typewritten-text component I published, I needed some styles in the Light DOM and ended up deciding to just release the stylesheet standalone so the developer can determine how to integrate it into their specific pipeline. This was to follow Open WC's recommendation to export side effects separately, which seemed tangentially related at the time.

Collapse
cjc profile image
Cameron Author

Thanks for that Open WC link, sounds like a good practice.

For this particular component there is so little styling involved that the <link> element would be larger than the CSS . The allure of elegance can make it hard to stick to your principles.

I'm rapidly discovering that a lot (all?) of the nuance for web components is in the packaging/delivery.

Collapse
joehonton profile image
Joe Honton

I've been using CSS variables inside components for important user-customizable options such as color scheme, size and position. For example, the rwt-storyboard component lets users set things like this:

rwt-storyboard {
    --font-basis: 1.0;
    --width: calc(10rem * var(--font-basis));
    --height: calc(40rem * var(--font-basis));
    --color: var(--white);
    --background: var(--black);
    --button-color: var(--pure-white);
}
Enter fullscreen mode Exit fullscreen mode