Back to Lit

11

packages/lit-dev-content/site/tutorials/content/wc-to-lit/11.md

latest5.6 KB
Original Source

Why LitElement

There are still ways the code can be improved:

  1. If the vote property or attribute is changed, the rating property may also be changed which will result in calling render twice. Despite repeat calls of render being a very efficient, the browser is still needlessly calling that function twice.
  2. It is tedious adding new properties and attributes as it requires a lot of boilerplate code.

This is where LitElement comes in!

LitElement is Lit's base class for creating fast, lightweight web components that can be used across frameworks and environments. Next, take a look at what LitElement can do for the <rating-element>!

Defining A LitElement

Start by importing and subclassing the LitElement base class from the lit package<ts-js> <span slot="js">.</span> <span slot="ts">, and use the @customElement decorator to replace the customElements.define call. </span> </ts-js>

rating-element.<ts-js></ts-js>

{% switchable-sample %}

ts
import {LitElement, html, css} from 'lit';
import {customElement} from 'lit/decorators.js';

// Remember to extend LitElement
@customElement('rating-element')
export class RatingElement extends LitElement {
  // remove connectedCallback()
  // remove customElements.define at the end of the file
  // comment out the observedAttributes method. this will break
  // functionality for now, but it'll be addressed in the next step
  ...
js
import {LitElement, html, css} from 'lit';

// Remember to extend LitElement
export class RatingElement extends LitElement {
  // remove connectedCallback()
  // comment out the observedAttributes method for now this will break
  //   functionality for now, but we'll tackle that in the next step
  ...

{% endswitchable-sample %}

What's changed?

  • LitElement is imported.
  • LitElement is now the new base class for <rating-element>.
  • html is still imported.
  • css is imported.

The css tag function allows you to define CSS tagged template literals, which enable math, templating, and other features under the hood.

{% aside "info" "no-header" %}

For a comprehensive list of styling features, refer to the Lit Styles documentation.

{% endaside %}

Styling With Lit

Next, move the styles from the render method to Lit's static stylesheet:

rating-element.<ts-js></ts-js>

{% switchable-sample %}

ts
export class RatingElement extends LitElement {
  static styles = css`
    :host {
      display: inline-flex;
      align-items: center;
    }

    button {
      background: transparent;
      border: none;
      cursor: pointer;
    }

    :host([vote=up]) .thumb_up {
      fill: green;
    }

    :host([vote=down]) .thumb_down {
      fill: red;
    }
  `;
  ...
  // remove <style> from render method
js
export class RatingElement extends LitElement {
  static styles = css`
    :host {
      display: inline-flex;
      align-items: center;
    }

    button {
      background: transparent;
      border: none;
      cursor: pointer;
    }

    :host([vote=up]) .thumb_up {
      fill: green;
    }

    :host([vote=down]) .thumb_down {
      fill: red;
    }
  `;
  ...
  // remove <style> from render method

{% endswitchable-sample %}

This is where most styles live in Lit.

Where available, Lit uses browser features such as Constructable Stylesheets to provide faster rendering times for your styles.

Render

Next, render() is a LitElement lifecycle method which requires us to return a Lit template and no longer needs to check for the shadow root:

rating-element.<ts-js></ts-js>

{% switchable-sample %}

ts
render() {
  return html`
    <button
        class="thumb_down"
        @click=${() => {this.vote = 'down'}}>
      <svg xmlns="http://www.w3.org/2000/svg" height="24" viewbox="0 0 24 24" width="24"><path d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v2c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"/></svg>
    </button>
    <span class="rating">${this.rating}</span>
    <button
        class="thumb_up"
        @click=${() => {this.vote = 'up'}}>
      <svg xmlns="http://www.w3.org/2000/svg" height="24" viewbox="0 0 24 24" width="24"><path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2z"/></svg>
    </button>`;
}
js
render() {
  return html`
    <button
        class="thumb_down"
        @click=${() => {
          this.vote = 'down';
        }}>
      <svg xmlns="http://www.w3.org/2000/svg" height="24" viewbox="0 0 24 24" width="24"><path d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v2c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"/></svg>
    </button>
    <span class="rating">${this.rating}</span>
    <button
        class="thumb_up"
        @click=${() => {
          this.vote = 'up';
        }}>
      <svg xmlns="http://www.w3.org/2000/svg" height="24" viewbox="0 0 24 24" width="24"><path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2z"/></svg>
    </button>`;
}

{% endswitchable-sample %}

Now you have a styled element! In the next step you will make the element react to property and attribute changes.