Groups

Namespaces related fields into one actor-facing surface.

typography = group({
  fontSize: signal(48),
  color: signal("#ffffff"),
});

group is organization, not state. The fields inside it are ordinary signals; the group just gives them a shared name so card.typography.fontSize() reads better than card.typographyFontSize().

Use it for

  • The canonical groups every LayoutActor already declares — layout, transform, appearance, flexItem, gridItem.
  • Actor-local groupings like content, typography, dock or reveal.
  • Keeping an actor readable when it has more than a handful of fields.
export class Desktop extends LayoutActor<typeof desktopSlots> {
  public dock = group({
    items: signal<DockItem[]>([]),
    position: signal<DockPosition>("bottom"),
    highlights: signal<Record<string, number>>({}),
  });

  public mouse = group({
    x: signal(0),
    y: signal(0),
    visible: signal(true),
    clickProgress: signal(0),
  });
}

layoutGroup

layoutGroup is the specialized form for the canonical layout box. Override it to change an actor's default geometry:

export class Image extends LayoutActor {
  layout = layoutGroup({ width: 320, height: 180 });
}

layout.x, layout.y, layout.width and layout.height accept numbers, pct(n), or percentage strings like "50%". Resolved output — localLayout() and worldLayout() — is always numeric.

Groups are not state boundaries

A group does not change how a value animates, resolve differently, or create any kind of scope. If you need nested values that animate independently as one bag, that is reactiveSignal.

On this page