This document explains what core/CustomElement.js provides, why it exists,
and how the fluent API reduces author code without a build step.
- Provide observable properties with attribute reflection.
- Provide a template composer + render pipeline.
- Provide a fluent API for definition without decorators or transpilers.
- Provide consistent lifecycle hooks (
constructed,connected,disconnected). - Keep author code short while still supporting JSDoc typing.
- Fluent chains configure a class without mutating the base.
- Class syntax uses
static {}or post-class configuration. - Observed props should not be declared as class fields.
- For usage examples and gotchas, see
creating-custom-elements.md.
observe()andprop()create accessor-backed properties on the prototype.- Accessors feed
render.byProp(...)for incremental updates. - Observable props reflect to attributes by default (except object-like types).
- Attribute reflection requires static-phase setup (fluent chain or
static {}).
this.observe({ count: { type: 'integer', value: 0 } });
this.prop('label', { type: 'string', value: 'ok' });.methods({ ... })attaches instance methods in fluent API.- Class API uses normal class methods.
.expressions({ ... })defines computed getters for templates.
.html\...`appends a template into theComposition`..css\...`appends styles into theComposition` (tagged template syntax).Composition.render()handles initial render and incremental updates.
onConstructed(fn)onConnected(fn)onDisconnected(fn)on('composed', fn)for composition-time hook- Hooks receive
callbackArguments.
- JSDoc typing works without a build step.
- Fluent API reduces annotation noise compared to class fields.
- See
test/core/custom-element.test.jsfor parity coverage.
extend(customExtender?): clone/extend a class without mutating the base.mixin(fn): apply a mixin to the current class.setStatic(source): assign static fields directly to the class.register(name?)/autoRegister(name): define the element withcustomElements.observedAttributes: platform hook for attribute callbacks.define(props)/set(source)/readonly(source): define prototype props.undefine(name): remove a prototype property and unregister observers.propList/attrList: maps of observable and attribute props.
observe(props): define multiple observable props.prop(name, options)/props(...): define one observable prop.idl(name, options): alias ofprop.defineStatic(props): define observable properties on the class itself.setPrototype(name, options): create accessor + returnnullfor typing.
html\...`: append a template into theComposition`.css\...`: append styles into theComposition` (tagged template syntax).css(...): programmatic form for string/array/stylesheet inputs.append(...): appendCompositionparts directly.recompose(cb): hook after composition step.
methods({ ... }): attach instance methods (fluent API).expressions({ ... }): attach derived getters.overrides({ ... }): define prototype overrides with typing.
events(listeners, options?): composition-level listeners.childEvents(map, options?): scoped child element events.rootEvents(listeners, options?): scoped to shadow root.on(nameOrCallbacks, callback?): register lifecycle + prop/attr hooks.onPropChanged(options)/onAttributeChanged(options): prop/attr callbacks.
registrations: map of registered element names to classes.defined,elementName: registration state helpers.interpolatesTemplate: template configuration flag.supportsElementInternals,supportsElementInternalsRole: feature flags.
render(...): initial render + incremental updates.render.byProp(...): targeted updates for a single prop.patch(patch): apply JSON merge patch, then render.propChangedCallback(...): internal prop update hook.attributeChangedCallback(...): standard hook, extended by CustomElement.connectedCallback()/disconnectedCallback(): standard hooks, extended by CustomElement.compose()/composition: composition creation and access.refs: id lookup proxy with WeakRef caching.attributeCache: parsed attribute cache (Map).callbackArguments:{ composition, refs, html, inline, template, element }.
refs.fooBarresolvesid="foo-bar"in the template/rendered DOM.- Before interpolation,
refsuses the template and#refsCompositionCache. - After interpolation,
refsuses the live DOM and#refsCache.