DEV Community

Discussion on: Let's Build Web Components! Part 5: LitElement

Collapse
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦 • Edited

Hey, sure

So, properties exist on the DOM, which is the browser's JavaScript object representation of the Document, but they don't exist at all in the document's HTML markup.

One big difference between the two is that (for the most part), CSS can't see the DOM, it can only see the markup.

@customElement('x-l')
class XElement extends LitElement {
  @property({ type: Boolean, reflect: true })
  schwifty = false;

  render() {
    return html`
      <button @click="${this.onClick}">
        Get ${this.schwifty ? 'un' : ''}schwifty
      </button>
    `;
  }

  onClick() {
    this.schwifty = !this.schwifty;
  }
}

Here, we use reflect: true in the property descriptor for XElement#schwifty to indicate that setting the property should reflect to the attribute.

That could be useful for a document author, for example with this css:

x-l[schwifty] {
  background: url('https://media.giphy.com/media/eNpXWzGIMRjIo4lXT8/giphy.gif');
}

Another use case along these lines could be setting a disabled attribute, or setting ARIA attributes based on an element's DOM state. I set the error attribute based on a caught error's message property in <stripe-elements>, as a convenience while debugging.

You can similarly think of cases where a component author would specifically not want to leak internal state outwards to the document, like when some intermediate value is observed so that it causes re-render, while remaining a private 'implementation detail' of the element:

const handleAsText = res => res.text();

@customElement("tpl-include")
export class TplInclude extends LitElement {
  @property({ attribute: false }) content;

  _template;

  @property({ type: String })
  get template() { return this._template; }
  set template(template) {
    let currentValue = this.template;
    this._template = template;
    this.fetchContent();
    this.requestUpdate('template', currentValue);
  }

  async fetchContent() {
    this.content =
      await fetch(this.template)
        .then(handleAsText);
  }

  render() {
    return (
        !this.content ? html`<span>Loading...</span>`
      :  html`${unsafeHTML(this.content)}`
    );
  }
}
Collapse
 
charles_lukes profile image
Son DotCom 🥑💙

Thank you!

Thread Thread
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦

Small edit to the second example: set content descriptor with attribute: false, It can only be set with a property now