Children

Declared occupants of slots, including owner-aware factories for live parent-to-child bindings.

A child declaration names the occupant of a slot. The field name selects the slot.

class Phone extends LayoutActor<typeof phoneSlots> {
  static slots = phoneSlots;

  statusBar = child(StatusBar); // occupies the "statusBar" slot
  app = child(MailApp); // occupies the "app" slot
}

Static overrides

Pass an overrides object for fixed initial state:

statusBar = child(StatusBar, { carrier: "MotionActor", batteryPct: 82 });

Owner-dependent overrides

Pass a factory instead when the child's inputs depend on the parent. The derived values continue to read the owner during resolution, so the binding stays live rather than being a one-time copy at spawn.

class Row extends LayoutActor<typeof rowSlots> {
  static slots = rowSlots;

  label = child(TextBlock, (owner: Row) => ({
    content: derived(() => owner.title()),
    layout: { width: derived(() => owner.layout.width()) },
  }));
}

This is the form people miss

The instinct is to drop into onSpawn() and wire the child by hand. Don't — an owner-aware factory keeps the child a declared field, keeps the binding live, and keeps the structure visible to the type system. Save onSpawn() for children that are genuinely conditional.

Dynamic children

Use hostInSlot(...), optionally in onSpawn(), when children are conditional or data-driven:

onSpawn() {
  if (this.showToolbar()) {
    this.hostInSlot("chrome", Toolbar);
  }
}

Reading a child

A declared child is a typed field, so it reads like any other property — and it can be returned as a scene export:

return { card, caption: card.caption };
const { caption } = compiled.at(frame).scene;
caption.text; // typed

On this page