Theme Framework How the LeaseLeads theme frontend works

Instantiable

The base class every behaviour extends — the element-backed instance model.

On this page 5

Every behavioural thing in the theme — a Module, a Layout, a sub-component — is an element backed by an instance. Instantiable is the base class that owns that pairing. It keeps a registry of which element maps to which instance, reads the element's options on construction, and runs the lifecycle. You subclass it, give it a selector, and the rest of the framework knows how to find, build, and drive your class.

Note

A Utility (the standard library — Traits, AssetLoader, Observers) is not element-backed and does not extend Instantiable. The dividing line is exactly that: a Component is an element; a Utility is cross-cutting logic that isn't tied to one.

How you subclass it

Declare a class, give it a static selector, and put your behaviour in lifecycle methods. That's the whole surface.

js
class Intro extends Instantiable {
  static selector = '.intro'

  async init() {
    // wire behaviour — runs once the element's declared assets have loaded
  }
}

You almost never call new Intro(...) yourself. The framework instantiates your class for you when its selector is found on the page (see The AssetLoader pipeline), and hands you back the same instance every time anyone asks for that element again.

The per-class registry

Each subclass owns a lazy Map of element → instance. Two calls for the same element return the same object — instances are unique per element, never duplicated. You never build or read that Map directly; you reach it through the static API:

Call What it does
Intro.make(el) Construct (or return the cached) instance, register it, fire created.
Intro.instance(el) Same, but reads as "give me the instance for this element."
Intro.get(el) The registered instance, or undefined — no construction.
Intro.has(el) Whether one is registered.
Intro.load() make() every element matching the static selector.
Intro.destroy(el) Run the instance's destroy and drop it from the registry.

make is the gate everything funnels through, and it is idempotent — the second call for an element returns the object the first one built, so reaching for an instance is always safe:

js
const intro = Intro.make(el)   // constructs and registers, or…
const same  = Intro.make(el)   // …returns the very same instance — never a duplicate
Note

Why it works this way. The registry is not just internal bookkeeping — it is the theme's external API. Because make/instance always return the one instance per element, a script injected from outside the theme can reach a live, already-booted instance and drive it: components.get('Intro').get(el).open(). See The Globals registry.

Options come from the element

On construction, Instantiable reads the element's data-* attribute, JSON-parses it, and stores the result as this.options. This is how PHP passes per-instance config (Splide settings, flags) into JS without a front-end dev touching the backend.

js
static parseOptions(element) {
  // reads element.dataset by dataKey → moniker → name, JSON.parses it,
  // and falls back to the class `defaults`
}

The attribute is keyed by the class's dataKey, then its moniker, then its name — so <div class="intro" data-intro='{"loop":true}'> lands as this.options.loop === true. Override static get defaults() to supply a baseline when the element carries no attribute, and settings(options) to reshape the merged result.

Tip

A data-* attribute is for scalar config. A larger collection (gallery items, map markers) travels as a data island — a <script type="application/json"> child the host reads with this.element.querySelector(':scope > script'). Reach for the attribute for flags and knobs; reach for the island for payloads.

A component with no behaviour

The floor is low. A class with only a static selector and nothing else is still useful — its single job is to pull its colocated .scss into the bundle through the JS import side-effect. OneFold is exactly this: a CSS-only component, no lifecycle, no options, just a selector that makes its styles ship when the page needs them.