| Custom element class |
Defines behavior by extending HTMLElement (or a built-in). |
class XThing extends HTMLElement {
constructor(){ super(); }
}
|
| Lifecycle callbacks |
Hooks for setup/teardown and reacting to changes. |
connectedCallback(){ /* init */ }
disconnectedCallback(){ /* cleanup */ }
static get observedAttributes(){ return ['value']; }
attributeChangedCallback(n,o,v){ /* react */ }
|
Registration (customElements.define) |
Makes the class available as a tag with a dash. |
customElements.define('x-thing', XThing);
|
| Shadow DOM |
Encapsulates DOM & styles; optional but common. |
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `<div>...</div>`;
|
| Template |
Reusable markup cloned into the shadow root. |
const tpl = document.createElement('template');
tpl.innerHTML = `<style>:host{display:block}</style>`;
this.shadowRoot.append(tpl.content.cloneNode(true));
|
Scoped styling (:host, ::slotted) |
Style the host and projected children inside shadow. |
this.shadowRoot.innerHTML = `
<style>
:host { display:inline-block; }
::slotted(span.badge){ font-weight:bold; }
</style><slot></slot>`;
|
| Constructable Stylesheets |
Share CSS across instances via adoptedStyleSheets. |
const sheet = new CSSStyleSheet();
sheet.replaceSync(':host{contain:content}');
this.shadowRoot.adoptedStyleSheets = [sheet];
|
| Slots |
Project light-DOM content into the component. |
this.shadowRoot.innerHTML = `
<slot name="label"></slot> <slot></slot>`;
|
| Attributes ↔ properties |
Reflect external configuration into internal state. |
get value(){ return this._v ?? ''; }
set value(v){ this._v = String(v); this.setAttribute('value', this._v); }
|
Events (CustomEvent) |
Emit outputs so parents can listen and react. |
this.dispatchEvent(new CustomEvent('change', {
detail: { value: this.value }, bubbles:true, composed:true
}));
|
| Accessibility (ARIA & focus) |
Make it operable with keyboard/screen readers. |
this.setAttribute('role','button');
this.tabIndex = 0;
this.addEventListener('keydown', e => {
if(e.key==='Enter') this.click();
});
|
| Form-associated (advanced) |
Participate in forms (value, validity, labels). |
static formAssociated = true;
internals = this.attachInternals();
internals.setFormValue(this.value);
|
Styling hooks (::part, exportparts) |
Expose internals for external theming. |
<button part="btn">Go</button>
/* outside component */
x-thing::part(btn){ border-radius:.5rem; }
|