Learn / Groups
Groups
A group is not a rectangle drawn behind some nodes — it is a container the engine understands: members move together, collapse is reversible by construction, and nesting reflows parents around children.
Creating and membership
import { GroupModel } from '@grafloria/engine';
diagram.addGroup(new GroupModel({
id: 'ingest-stage',
position: { x: 0, y: 0 }, size: { width: 320, height: 180 },
}));
await engine.addToGroup('ingest-stage', 'a'); // (groupId, entityId) — group first
await engine.addToGroup('ingest-stage', 'b');
await engine.removeFromGroup('ingest-stage', 'b');
Members drag with the group, and interactive membership works too — drag a node
into a group's frame and it joins; groups can contain groups. Query structure with
diagram.getGroups(), diagram.getGroup(id),
diagram.getAncestors(id) / getDescendants(id).
Collapse is a reversible snapshot
await engine.collapseGroup('ingest-stage'); // members hide, links re-route to the header
await engine.expandGroup('ingest-stage'); // everything returns exactly where it was
Collapse stores a snapshot on the group — member world-positions and the links removed at collapse time — so a collapsed diagram serializes, round-trips, and expands correctly later, even in a different session. Links from outside to a hidden member re-anchor to the collapsed header, and parallel edges merge into one until expand.
Nesting and fit
Containers reflow: a group can fit itself around its already-fitted children, and a resize cascades down into nested containers' own reflows. That is what makes swimlanes, BPMN pools and stage-based pipelines behave — moving a lane moves its contents; growing content grows the lane.
Zones — a frame of your own
A group declared in the render spec is a zone: a tinted region around some
boxes with a small caption in a corner — no title band. bounds pins its
frame; without it the frame is fitted around children with
padding. The children become its members.
A zone is a container you can pick up. Press its caption or its empty tint and drag: the zone moves with every box in it, and their lines follow (empty canvas outside a zone still pans). Drag a box out of a zone and it leaves; drop one inside and it joins. Both are on by default; a host that draws frames purely as decoration turns them off:
api.getEngine().setInteractionConfig({
enableGroupDrag: false, // a press on a zone pans the canvas instead
enableGroupMembershipOnDrop: false, // dropping a box never changes its zone
});
const api = render({
nodes, edges,
groups: [{
id: 'ours', label: 'OUR SIDE · MUST NEVER SEE A CARD', children: ['api', 'db'],
bounds: { x: 380, y: 236, width: 566, height: 150 },
labelPlacement: 'bottom-left', // top-left (default), top, top-right, bottom-…
style: { fill: '#f3f4f6', stroke: '#d7dbe0', strokeDasharray: '5 4',
color: '#4b5563', fontWeight: '700', letterSpacing: 1 },
}],
}, el);
api.setGroups([...]); // reconcile later, like setNodes
A Mermaid subgraph is the same zone: style <subgraph> …
styles its frame, and a subgraph no directive pins is fitted around its nodes.
Frameless groups — layout without chrome
const g = diagram.getGroup('kpi-row');
g.setMetadata('frameChrome', 'none'); // no border, no header — pure layout container
A frameless group is the primitive under the dashboard kit's grid: cells that pack and drag without looking like "a group". Use it whenever you want container behavior without container pixels.
Live: group demos — drag in, collapse, nest →