Search code examples
web-componentlit-elementlit

How to use packaged styles in a lit web component?


If I have a lit web component, how can I use styles (preferrably sass) from another package in the component? Some examples below:

I want to import some helper mixins from an external library: Usually, I would import the library following documented instructions: https://www.npmjs.com/package/sass-rem

I'm assuming I would need to do something along the line of this, but I'm getting various syntax errors:

import { LitElement, css } from "lit";
import sassRem from 'sass-rem'; //Import dependency
import { customElement } from "lit/decorators.js";

@customElement("demo-sass-component")
export class DemoComponent extends LitElement {
  static override styles = [
    sassRem, // Reference dependency
    css`
      @use "rem" as *; // Use dependency

      .demo {
        font-size: rem(24px);
      }
    `,
  ];
}

I want to create a date picker which includes styles from a dependency: Similar to above, how would I encapsulate styles from an external library into my component?

I imagine I could answer both of these question by using unsafeCSS - is this really the correct way? Whilst in aware it "should" be safe given we're not importing use edited content, it still feels like something that should be used sparingly rather than as a common standard? Referencing unsafeCSS in every component made doesn't "feel" right, but equally I've found no other alternative so far...

import demoStylesfrom "./demo.scss?inline";

@customElement("demo-component")
export class Demo extends LitElement {

static override styles = [unsafeCSS(demoStyles)];

I'm using Vite for my build and strictest tsconfig settings.


Solution

  • There is absolutely no problem with using unsafeCSS() API to do this. It is simply about warning novice users from importing anything unsecure from the Web.

    If the use of this name concerns you, you can consider using adoptStyles() API provided by the Lit which accepts CSSStyleSheet object that you can build explicitly.

    import { adoptStyles } from 'lit';
    
    import demoStylesFrom "./demo.scss?inline";
    
    const sheet = new CSSStyleSheet();
    
    sheet.replaceSync(demoStylesFrom);
    
    @customElement("demo-component")
    export class Demo extends LitElement {
    
      override connectedCallback () {
        super.connectedCallback();
        adoptStyles(
          this.renderRoot,
          [demoStylesFrom]
        );
      }
    }