'litelement - how to compute style based on property or attribute values

I'm following the LitElement guide here but can't seem to get my custom element's style values calculated based on it's attribute.

I want my element to be written in one of following ways:

<my-element data="some values" darkmode></my-element>
<my-element data="some values"></my-element>

I want to style the element's background and text colour depending on whether dardmode attribute is set or not.

In my LitElement class, I created a corresponding property and also initialized it. But, in the static style, this.darkMode is always returning false. I think I'm missing something here but not sure what:

class MyElement extends LitElement {

    static get properties() {
        return {
            data:    { type: String },
            darkMode:   { type: Boolean }
        };
    }

    static get styles() {
        const background_color = this.darkMode ? css`#000` : css`#fff` ;
        const text_color = this.darkMode ? css`#fff` : css`#333333`;

        return [
            css`
            :host {
                display: block;
            }
            .data-container {
                font-family: "Roboto",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
                -webkit-font-smoothing: antialiased;
                -moz-osx-font-smoothing: grayscale;
                text-rendering: optimizeLegibility;
                background-color: ${background_color} !important;
                color: ${text_color} !important;
            }`
       ];

    constructor() {
        super();
        this.data = "";
        this.darkMode = false;
    }

    render() {
        return html`
           <div class="data-container">
               <p>${this.data}</p>
           </div>
        `;
    }
}

customElements.define('my-element', MyElement);



Solution 1:[1]

In this code:

static get styles() {
  const background_color = this.darkMode ? css`#000` : css`#fff` ;
  // ...

styles is a static method, so within it this refers to the MyElement class itself, so this.darkMode is the darkMode property of MyElement and not the darkMode property of any instance of MyElement. Of course, MyElement.darkMode is always undefined, so you always get the "light" styles.

A different and more maintainable approach would be to "reflect" the darkMode property to an attribute of the element with the reflect: true option and then use the CSS attribute selector [dark-mode] to override the "light" styles, e.g.:

.data-container {
  background-color: #fff;
  color: #333;
}
:host([dark-mode]) .data-container {
  background-color: #000;
  color: #fff;
}

You can see this working in the below snippet:

const { LitElement, css, html } = litElement;

class MyElement extends LitElement {
  static get properties() {
    return {
      data: { type: String },
      darkMode: {
        type: Boolean,
        reflect: true,
        attribute: 'dark-mode',
      },
    };
  }

  static get styles() {
    return css `
      :host {
        display: block;
      }
      .data-container {
        background-color: #fff;
        color: #333;
      }
      :host([dark-mode]) .data-container {
        background-color: #000;
        color: #fff;
      }
    `;
  }

  constructor() {
    super();
    this.data = "";
    this.darkMode = false;
  }

  render() {
    return html `
      <div class="data-container">
        <p>${this.data}</p>
      </div>
    `;
  }
}

customElements.define('my-element', MyElement);
<script src="https://bundle.run/[email protected]"></script>

<my-element data="some dark values" dark-mode></my-element>
<my-element data="some light values"></my-element>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1