loading...
Cover image for LitElement: using web components

LitElement: using web components

link2twenty profile image Andrew Bone ใƒป3 min read

On February the 5th Google announced LitHTML was, finally, at version 1 and LitElement had reached version 2. To celebrate I'm going to have a look at web components and, using the guide, convert my material design switches into elements.

The aim is to be able to just write some simple HTML and get a simple, nice and accessible toggle switch back. I'll be using JSFiddle to show the various steps.

<md-switch>Toggle switch</md-switch>

example

Create

This part has 3 steps that we'll need to work through in order to register our element. We do these steps in Javascript.

  • Import the LitElement base class and html helper function.
  • Create a class for your element that extends the LitElement base class.
  • Register the new element with the browser.

With importing the project I don't have it locally but know that I can see it hosted here https://unpkg.com/lit-element/lit-element.js?module which is why my import line says to get LitElement and html from there.

The most important, and hardest, part of any project is naming. When making a web component the name must contain a hyphen, like foo-bar, following general convention we should name our class the same as our element but with hyphens removed and each new word having a capital letter, like FooBar. Our project is called md-switch.

The render function defines your componentโ€™s template. You must implement render for every LitElement component.

Our render is a simple paragraph containing "Hello world!".

Finally, we need to register the element. This is where we let the browser know md-switch elements are associated with the MdSwitch class.

Customising

Now let's get the HTML for our switches. If you want to read about the logic behind the markup and the styles I suggest you read my older post linked above.

<label class="md_switch">
  <input type="checkbox" />
  <span class="md_switch__toggle"></span>
  Toggle switch
</label>

You'll notice the label text for the switch is static. This is where slots come in handy. They allow you to take the data/text between that tags in the html and 'slot' it into your template.

Properties

Now we'll look at properties. In reality, our switch is a stylised checkbox so needs all of the same properties/attributes. I'm only going to include checked and disabled for this example as they're the most important and will give you a good enough idea of how to implement more.

To add a property we need to add an object to contain them. The litElement way of doing this is with a static get called Properties.

Our object should contain checked and disabled these are both Boolean values and are both attributes of our element.

{checked:  { type: Boolean, attribute: true }}

This is good but now we need to pass these properties to our template. Because our properties are boolean we can use the ? operator, which looks like this:

?checked="${this.checked}"

Events

We don't have to do much with events on this project but we do want to keep our input's checked state and our elements checked state in sync. The easiest way to achieve this is to have an onchange event that updates md-switch's checked state when the input's changes.

The way we do this is with the @ operator. In our template we say @eventname="{this.functionName}" we want the change event so we'll use @change we'll also need a new function.

Style

To add our styles we need to add css to our initial import. Then we need a static get called styles that returns some CSS and that's it.

Fin

And that's all there is to it. Web components make reusing elements super easy but you don't have to make all your elements your self. There is a site called https://www.webcomponents.org/ which has thousands of elements you can use in your projects, some elements are better than others so be careful.

I hope this made sense to you and would love to see any elements you have made yourselves. Thanks for reading!

๐Ÿฆ„๐Ÿง ๐Ÿ’•๐Ÿฆ„๐Ÿฆ„๐Ÿ’•โค๐Ÿง ๐Ÿ’•โค

Posted on Feb 6 '19 by:

link2twenty profile

Andrew Bone

@link2twenty

A British Front-end developer, that is passionate about web accessibility.

Discussion

markdown guide
 

Awesome post. Way to go!

If you're using Rollup to bundle your app, you can import styles from CSS with this plugin:

npm.im/rollup-plugin-lit-css

import { LitElement, html } from 'lit-element';
import style from './my-element.css';

class MyElement extends LitElement {
  static styles = style;
  render() {
    return html`<h1>๐Ÿฐ</h1>`;
  }
}

Which is precisely equivalent to :

import { LitElement, css, html } from 'lit-element';
import { css } from 'lit-element';

class MyElement extends LitElement {
  static styles = css`/*... contents of my-element.css */`;
  render() {
    return html`<h1>๐Ÿฐ</h1>`;
  }
}

I hope this tides us over until the css modules proposal is implemented across browsers

 

It weirdly reminds me of VueJS: the html part looks a lot like the <template> (the @ syntax for events and <slots>), the css part reminds me of the VueJS <style> section and the class is the <script> section.

Cool :-)

 

This is great! One question, how would you pass in multiple parameters? Would it look something like this?

updateChecked({event, param2, param3}) {
      console.log(event, param2, param3);
      console.log((this.checked = event.target.checked));
    }

    render() {
      return html`
        <label class="md_switch">
          <input
            @change="${e =>
              this.updateChecked({
                event: e,
                param2: this.param2,
                param3: this.param3
              })}"
            ?checked="${this.checked}"
            ?disabled="${this.disabled}"
            type="checkbox"
          />
          <span class="md_switch__toggle"></span>
          <slot></slot>
        </label>
      `;
    }
 

I don't think you'd ever want to add more parameters with an event. Looking at your example the params were attached to this anyway so we can just get them with the function.

updateChecked(e) {
  console.log(e, this.param2, this.param3);
}

render() {
  return html`
    <label class="md_switch">
      <input
        @change="${this.updateChecked}"
        ?checked="${this.checked}"
        ?disabled="${this.disabled}"
        type="checkbox"
        />
      <span class="md_switch__toggle"></span>
      <slot></slot>
    </label>
  `;
}