DEV Community

Cover image for LitElement: using web components
Andrew Bone
Andrew Bone

Posted on

LitElement: using web components

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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 }}
Enter fullscreen mode Exit fullscreen mode

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}"
Enter fullscreen mode Exit fullscreen mode

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!

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

Top comments (4)

Collapse
 
bennypowers profile image
Benny Powers ๐Ÿ‡ฎ๐Ÿ‡ฑ๐Ÿ‡จ๐Ÿ‡ฆ • Edited

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>`;
  }
}
Enter fullscreen mode Exit fullscreen mode

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>`;
  }
}
Enter fullscreen mode Exit fullscreen mode

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

Collapse
 
rhymes profile image
rhymes

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 :-)

Collapse
 
nathancourtney profile image
nathan-courtney

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>
      `;
    }
Collapse
 
link2twenty profile image
Andrew Bone

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>
  `;
}