Advanced API
Methods that the average app never reaches for, but that exist for testing, devtools, manual mounting, and bespoke loaders.
Lego.snap()
Manually mount a block element. Equivalent to what connectedCallback does for elements inserted into the light DOM.
Lego.snap(el: HTMLElement): voidSteps:
- No-op if
elis already snapped. - Clone the registered template, attach Shadow DOM, adopt stylesheets.
- Build the state proxy (script → template
b-logic→ instanceb-logic). - Walk the shadow tree, attach event listeners, scan for bindings, first render.
- Fire
mounted(). - Recursively snap nested registered blocks inside the shadow tree.
The most common reason to call snap() is inside another Shadow DOM, MutationObserver doesn't watch shadow trees, and the manifest/loader paths only re-fire for elements connecting to the light DOM tree.
const card = document.createElement('user-card');
container.shadowRoot.appendChild(card);
Lego.snap(card); // observer didn't see it; do it manuallyLego.unsnap()
Tear down a block. Symmetric to snap().
Lego.unsnap(el: HTMLElement): voidSteps:
- Fire
unmounted(). - Remove all event listeners attached via
@eventandb-sync. - Disconnect
IntersectionObserverinstances fromb-enter/b-leave. - Clean up
$dbbindings on the element. - Drop the element from
activeBlocksandglobalSubscribers. - Break circular refs (
$element,$vars,$emit,$parent,$route,$go,$mount). - Recursively unsnap child blocks.
Calling unsnap() is rarely needed, element removal triggers disconnectedCallback, which calls it for you. Use it explicitly when you're swapping content programmatically and want clean teardown before reattachment.
Lego.mount()
Imperative mount. Powers both b-mount and the global $mount helper.
Lego.mount(
tagName: string | null,
target?: string | HTMLElement | HTMLElement[],
props?: object
): HTMLElement | HTMLElement[] | undefined| Form | Effect | Returns |
|---|---|---|
mount('user-card') | Create a detached <user-card> | the element |
mount('user-card', '#main') | Clear #main, mount one <user-card> | the element |
mount('user-card', '.row', { id: 1 }) | For each .row: clear, mount with $initialState = { id: 1 } | array (or single el) |
mount(null, '#main') | Clear #main (no mount) | undefined |
tagName must contain a hyphen (custom-element rules), otherwise a console warning is emitted and nothing is mounted.
props is injected onto the host element as $initialState before the element connects, so mounted() can see them via the merge into state.
Lego.db()
Persistence factory. Returns a descriptor that can be:
- assigned into block state (acts as a reactive, persisted property);
- used directly to read/write the underlying storage.
Lego.db(key: string): {
default(v: any): this; // init-time, fluent
debounce(ms: number): this; // init-time, fluent
set(value: any, debounceMs?: number): any; // runtime
get(): any; // runtime
delete(): boolean; // runtime
}As a reactive state property
When the descriptor is assigned to a key inside a block's logic, the runtime hydrates it into a regular reactive value: any read from localStorage is performed at mount time, and any subsequent write to the property is debounced and persisted.
{
theme: $db('theme').default('light'),
draft: $db('draft.signup').default('').debounce(500)
}<select b-sync="theme">
<option>light</option>
<option>dark</option>
</select>Cross-tab sync is automatic, every other tab with bindings to the same key receives the new value via the storage event.
Direct usage from JS
Lego.db('user').set({ name: 'Alice' }); // immediate write
Lego.db('user').set({ name: 'Bob' }, 200); // debounced write
const u = Lego.db('user').get(); // synchronous read
Lego.db('user').delete(); // remove + notifyLego.db is also exposed as Lego.globals.$db and as $db inside expression scope.
Quota handling
When a write exceeds localStorage quota, the runtime evicts the oldest tracked keys (FIFO) to free at least 2× the space needed, then retries. Eviction only applies to keys this app wrote, third-party localStorage usage is left alone. If eviction can't free enough space, config.onError is called with type: 'quota-critical'.
Introspection
Lego.getLegos(): string[] // all registered tag names
Lego.getActiveBlocksCount(): number // currently snapped blocksDebug
Lego.debug.stylesheets(el: HTMLElement): { explicit: string[]; inherited: string[]; applied: string[] } | nullReturns the stylesheet keys that resolved for an element, what was declared on the template, what cascaded in from ancestors, and the deduped final list. null if the element hasn't been snapped or doesn't carry stylesheet metadata.
Lego.debug.stylesheets(document.querySelector('user-card'));
// { explicit: ['cards'], inherited: ['design-tokens'], applied: ['design-tokens', 'cards'] }