CHEAT SHEET
WEB COMPONENTS
Created by @Manz ( https://twitter.com/Manz ) https://lenguajejs.com/
T Template Inert document fragment ES S Slots External slots
HTML TAG ES SIMPLE SLOT
<template> inert tag for html content ES <slot> external html to inside component
<template shadowroot="open"> <slot>��slot>
#DOCUMENT-FRAGMENT declarative
shadow dom C Custom Elements HTML Components NAMED SLOT
<div>...��div> <slot name="text"> multiple html to inside
HTML STRUCTURE
��template>
<prefix-component> custom html tag <slot name="title">��slot>
API TEMPLATE HTMLTemplateElement
DF .content ref to document fragment node <base-name attribute="value"> CSS HTMLTemplateElement
SR .shadowRoot shadow dom root node <div>content��div> SHADOW DOM ::slotted(selector) style to slotted tags
<div>content��div> LIGHT DOM EVENTS HTMLTemplateElement
D DOM HTML Access DOM manipulation ��base-name> slotchange detect slot-element changes
API HTML CLASS API JS PROPERTIES & METHODS <base-name>
s .innerHTML get/replace HTML markup o constructor() initial method super() <h2 slot="title">Default��h2>
s .outerHTML idem (includes HTML tag) public() public properties/methods <p slot="description">Text��p>
s .textContent get/replace text content #private() private properties/methods ��base-name>
MULTIPLE SLOT SIMPLE SLOT
element.innerHTML = `<div>text��div>`; class BaseName extends HTMLElement {
CREATE HTML / ADD ELEMENT ... C CSS in WebComponents Styles (CSS)
e document .createElement(tag) create node } CSS WITHOUT SHADOW DOM GLOBAL CSS
customElements.define("base-name",BaseName) connectedCallback() {
document.createElement("div"); COMPONENT LIFECYCLE HOOKS WHEN? this.innerHTML = `
connectedCallback() added to DOM <style>p { color: red; }��style>
o .appendChild(child) add inside element `;
disconnectedCallback() remove from DOM
element.appendChild(node); adoptedCallback() move to new doc. }
CSS WITH SHADOW DOM LOCAL CSS
INSERT HTML / ELEMENT class BaseName extends HTMLElement {
constructor() { connectedCallback() {
.insertAdjacentHTML(pos, html) add super(); this.shadowRoot.innerHTML = `
el.insertAdjacentHTML("afterend", ... don't forget <style>p { color: red; }��style>
} super() on `;
`<div><p>Content��p>��div>`); constructor
connectedCallback() { ... } }
disconnectedCallback() { ... }
.insertAdjacentElement(pos, node) CSS CONTAINER
adoptedCallback() { ... }
el.insertAdjacentElement("afterend", node); } :host style custom element (container)
customElements.define("base-name", BaseName) :host(selector) idem, if match container
beforebegin afterend ATTRIBUTE OBSERVATION :host-context(selector) idem, ancestor
html tag
<div> text ��div> position to a get observedAttributes() notify changes CSS PARTS
insert
attributeChangedCallback(attr, old, now) <span part="name"> define part
afterbegin beforeend
class BaseName extends HTMLElement {
<span part="name">��span>
F Find HTML Elements DOM search static get observedAttributes() {
return ["name1", "name2"]; ::part(selector) style surface parts
TRADITIONAL DOM SEARCH API
}
o document .getElementById(id)find by #id attributeChangedCallback(name, old, now){ S Shadow DOM .shadowRoot (DOM isolate)
a .getElementsByName(name) name attr ... fire this callback when a WEBCOMPONENT WITHOUT SHADOW DOM
} observed attribute changes
a .getElementsByClassName(class) .class } class BaseName extends HTMLElement {
a .getElementsByTagName(tag) html tag customElements.define("base-name", BaseName) constructor() {
document.getElementById("name"); CUSTOM ELEMENTS REGISTRY GLOBAL REGISTRY super();
this.innerHTML = `<div>��div>`;
MODERN DOM SEARCH API customElements .define(name, class) reg
}
o customElements .get(name) register elem
o .querySelector(selector) return first elem }
customElements .upgrade(node) update el.
a .querySelectorAll(selector) ret all elems WEBCOMPONENT WITH SHADOW DOM
p customElements .whenDefined(name) fire.
o .closest(selector) return closest ancestor s .attachShadow(options) add shadow dom
b .matches(selector) matches with elem? C Custom Events Send/Receive events SHADOW DOM OPTIONS
document.querySelector(".menu > p"); CUSTOM EVENTS API
s mode encapsulation mode open closed
HTML ATTRIBUTE API b .dispatchEvent(event) send event b delegatesFocus shadow get focus false
b .hasAttributes() element w/attributes? CUSTOM EVENT OBJECT
class BaseName extends HTMLElement {
s .getAttributeNames() return attrs array o .detail data object with information constructor() {
b .hasAttribute(name) check attribute b .bubbles bubbles up through the DOM super();
s .getAttribute(name) return value attr b .composed send across shadow DOM this.attachShadow({ mode: "open" });
.removeAttribute(name) delete attribute this.shadowRoot.innerHTML = `<p>��p>`;
const event = new CustomEvent("message", {
}
.setAttribute(name, value) modify attr detail: { ... },
}
b .toggleAttribute(name, force) add/del bubbles: true,
composed: true
element.setAttribute("name", "value"); });
CHEAT SHEET
LIT-ELEMENT/LIT-HTML lit-html
Created by @Manz ( https://twitter.com/Manz ) https://lenguajejs.com/
T Templates Next-gen lit-html templates C Component Lit-Element web component P Properties Properties != Attributes
SETUP & CONFIGURATION SETUP & CONFIGURATION PROPERTIES DECLARATION SYNTAX
<script type="module"> <script type="module"> static get properties() {
import { html, render } from "..."; import { LitElement, html } from "..." return {
��script> ��script> prop1: { type: String, ... },
LIT-HTML SIMPLE TEMPLATES DEFINE COMPONENT LIT-ELEMENT
prop2: { type: Boolean, ... }
}
TR html`code` create HTML template class BaseName extends LitElement {
}
render`template, element` update page ...
PROPERTIES OPTIONS
}
const tpl = html`<div>Hello��div>`; customElements.define("base-name", BaseName) o type hint for convert between props/attr
render(tpl, document.body); BASIC LIFECYCLE HOOKS WHEN? o converter custom func or object props/attr
LIT-HTML DYNAMIC TEMPLATES
update(props) reflect prop to attr & render f fromAttribute(value, type) convert to prop
TR html`code, ...values` template with data if override, super.update(props) or no render f toAttribute(value, type) convert to attr
render`template(val), element` update TR render() use lit-html to render template f hasChanged(now, old) true=requestUpdate
b attribute associate prop with a attribute
const p = (t) �� html`<p>${t}��p>`; class BaseName extends LitElement {
render(tpl("Text"), document.body); constructor() { b noAccessor avoid generate def. accesor
super(); b reflect autoset prop value to attribute
HELPERS (BIND) ...
<tag value=${var}> string attribute } don't forget
connectedCallback() { call super on S Styling CSS in Components
<tag ? disabled=${var}> boolean attribute super.connectedCallback();
parent hooks
SETUP & CONFIGURATION
<tag . value=${obj.value}> bind object value }
<script type="module">
<tag @ event=${func}> bind event to func. update() { ... }
render() { import { ..., html, css } from "..."
CONDITIONALS (TERNARY) / NESTED TEMPLATES
html`<div>Component �div>`; ��script>
html`${user.logged } STYLES IN COMPONENTS ALL INSTANCES
? html`Welcome ${user.name}` }
customElements.define("base-name", BaseName) var(--name) set css variable from in/out
: "User not logged in" nothing
}`;
ADVANCED LIFECYCLE HOOKS WHEN? ${var} set javascript variable
LOOPS
p requestUpdate() manually start an update CR unsafeCSS(css) set unsafe css code
MAP LOOP p requestUpdate(propName, old) prop setter static get styles() {
--theme: ...
html`<ul>${ performUpdate() microtask after ev.loop return css`
arr.map(item �� html`<li>${item}��li>`) b shouldUpdate(props) update proceed :host { color: var(--theme) }
}��ul>`; firstUpdate(props) called on first update div { color: red } css`...`
ARRAY LOOP
updated(props) DOM updated & rendered button { color: ${bgColor} }
for (const item of items) { `;
p .updateComplete true=no pending updates
arr.push(html`<li>${item}��li>`); } return [super.styles, css`...`, css`...`]
} shouldUpdate
html`<ul>${arr}��ul>`; el.prop = "..." hasChanged STYLES IN COMPONENTS SPECIFIC INSTANCES
update
D Directives render() {
lit-html/directives/name.js render
performUpdate requestUpdate return html`
DIRECTIVES
firstUpdate <style>
TR asyncAppend(iterable) async add data resolve updateComplete div { color: red }
asyncReplace(iterable) async change data updated
TR ��style>
TR cache(code) cache DOM for a bind/input S Shadow DOM By default, uses ShadowDOM <div>Hello!��div>
o nothing render a empty text node LITELEMENT WITHOUT SHADOW DOM `;
o ifDefined(value) set value, else no-op class BaseName extends LitElement { }
o guard(deps, func) render func on change createRenderRoot() {
return this; D CSS Directives lit-html/directives/name.js
o live(value) update value (outside lit-html) } CLASSMAP
TR repeat(items, keyfn, tpl) repeat template }
import { classMap } from "...";
REPEAT DIRECTIVE
D Decorators Typescript or Babel needed const classes = { selected : true };
import { repeat } from "..."; DECORATORS const result = html`
html`<ul>${repeat(items, <div class=${classMap(classes)}>
(items) �� items.id, import { customElement, property } ...
Content
(item) �� html`<li>${item.name}��li>`)}
��ul>`; @customElement("base-name") ��div>
class BaseName extends LitElement { `;
TR templateContent(tag) render <template>
@property() STYLEMAP
TR unsafeHTML(html) render unsafe code prop1 = "value"; import { styleMap } from "...";
TR unsafeSVG(svg) render unsafe svg code prop2 = "value"; const styles = { color : "red" };
TR until(...values) render w/priority (1=more) ... const result = html`
UNTIL DIRECTIVE render() { <div style=${styleMap(styles)}>
import { until } from "..."; html`<div>Component��div>`; Content
html`${until(fetchPromise, } ��div>
html`<p>Loading...��p>` )}`; } `;
https://unpkg.com/lit-element?module https://cdn.skypack.dev/lit-element
https://unpkg.com/lit-html/directives/class-map.js?module https://cdn.skypack.dev/lit-html/directives/class-map.js