DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

eleonorarocchi
eleonorarocchi

Posted on • Updated on

Lit: how can a lit component be defined

Creating a Lit component involves a number of concepts:

  • It is implemented as a custom element and registered in the browser.
  • It has a render method called to render the component content, in which you define a template.
  • Properties maintain the state of the component. The modification of one or more reactive properties of the components triggers an update cycle that takes care of re-rendering the component.
  • A component can define encapsulated styles to control its appearance.
  • Lit defines a set of callbacks that can be overridden to hook into the component lifecycle, for example to run code when the element is added to a page or whenever the component is updated.

How to define a Lit component

A class that extends LitElement must be created and registered in the browser:
Image description

The @customElement decorator is an abbreviation for calling customElements.define, which registers a custom element class with the browser and binds it to an element name (in this case, simple-greeting).

Using JavaScript, or without using decorators, you can call define() directly:

Image description

A Lit component is an HTML element.

When defining a Lit component, you are defining a custom HTML element which can then be used as any integrated element:
Image description
Image description

The base class LitElement is a subclass of HTMLElement, therefore a Lit component inherits all properties of standard methods by HTMLElement.

Specifically, LitElement inherits from ReactiveElement, which implements reactive properties, and in turn inherits from HTMLElement.

We know that TypeScript is able to infer the class of an HTML element returned by some DOM APIs based on the tag name.

For example, document.createElement ('img') returns an HTMLImageElement instance with a src: string property.

You can achieve the same behavior on custom elements by adding to HTMLElementTagNameMap as follows:
Image description

In this way, the following code performs the type checks correctly:
Image description

It is always a good idea to add an HTMLElementTagNameMap entry to elements created in TypeScript and publish the .d.ts types in the npm package.

What the Render does

You can add a template to the component to define what should be displayed.

Templates can include expressions, which are placeholders for dynamic content.

To define a template for a Lit component, a render() method must be added:
Image description

You write the HTML template inside a Javascript tagged template literal using the Lit html tag function.

Template literals are a special type of string symbols that can contain Javascript expressions and span multiple lines. They use backtick characters instead of double quotes. It also accepts arbitrary expressions internally.

These templates can also be used as functions, by putting a keyword in front of the template string to "tag" it.

Image description

Lit templates can include JavaScript expressions.

You can use expressions to set text content, attributes, properties, and event listeners.

The render () method can also include any JavaScript, for example, you can create local variables for use in expressions.

Typically, the component's render () method returns a single TemplateResult object (the same type returned by the html tag function).

However, it can return anything that Lit can render:

  • Primitive values such as string, numbers or booleans.
  • TemplateResult objects created by the html function.
  • DOM nodes.
  • Arrays or iterables of any of the supported types.

To take full advantage of Lit's functional rendering model, the render () method should:

  • Avoid changing the component state.
  • Avoid producing side effects.
  • Use only component properties as input.
  • Return the same result when the same property values are assigned.
  • Avoid making DOM updates outside of render ().
  • Express the component model according to its state and acquire its state in the properties.

You can compose Lit templates from other templates.

For example, you can compose a template for a component called from smaller templates for the header, footer, and main content of the page.

Image description

In this example, individual templates are defined as instance methods, so a subclass could extend this component and override one or more templates.

You can also compose a template by importing other elements and using them in the template itself.

Image description

Image description

A Lit component renders its model initially when it is added to the DOM on a page.

After the initial rendering, any change to the component's reactive properties triggers an update cycle, re-rendering the component.

Lit updates in batches to maximize performance and efficiency.

Setting multiple properties simultaneously triggers a single update, performed asynchronously at the time of the microtask.

During an update, only the parts of the DOM that change are re-rendered.

Although Lit patterns resemble string interpolation, Lit parses and creates static HTML once, then only updates modified values in expressions, making updates very efficient.

Lit uses the shadow DOM to encapsulate the DOM that a component renders.

The shadow DOM allows an element to create its own isolated DOM tree, separate from the main document tree.

It is a key feature of the web component specification that enables interoperability, style encapsulation, and other benefits.

What is the shadow DOM

The shadow DOM allows web developers to create compartmentalized DOMs and CSS for web components.

The shadow DOM removes some of the frailties typical of building web apps, which stem from the global nature of HTML, CSS, and JS.

For example, when using a new HTML class / ID, it is not possible to tell if it will conflict with an existing name used by the page.

! Important multiplies in CSS, style selectors grow out of control, and performance can suffer.

The shadow DOM fixes CSS and DOM, introducing scoped styles.

Without tools or naming conventions, you can bundle CSS with markup, hide implementation details, and create self-contained components in vanilla JavaScript.

When the browser loads a web page, among other things, it transforms the HTML into a live document.

To understand the page structure, the browser parses the HTML (static text strings) into a data model (objects / nodes).

The browser preserves the HTML hierarchy by creating a tree of these nodes: the DOM, which is a live representation of a page. Unlike static HTML, the nodes produced by the browser contain properties, methods and can be manipulated by programs using JavaScript.

The Shadow DOM is simply a normal DOM with two differences:

  1. how it is created / used
  2. how it behaves relative to the rest of the page.

Normally, you create DOM nodes and add them as children of another element.

With Shadow DOM, you create a scoped DOM tree that is attached to the element, but separate from its actual children. This scoped subtree is called a shadow tree. The element it is attached to is its shadow host. Anything added in the shadows becomes local to the hosting element, including .</p> <p>This is how the shadow DOM gets the css style scope.</p> <p>If you want to read this content in italian, see <a href="https://www.slideshare.net/EleonoraRocchi1/lit2pdf">here</a>.</p>

Top comments (0)

🌚 Friends don't let friends browse without dark mode.

Sorry, it's true.