Skip to content
D
Documentation

Group nodes and containers

how-to
2 min readUpdated

Create a visible container and add nodes to its membership.

Use a group when a set of nodes needs a real container relationship, not only a decorative rectangle: the engine tracks membership. This page shows the task in JavaScript, Angular, Qwik, Vue, and React.

Unlike the mounted workflow graph in Build runnable workflows, this task adds explicit group membership: a node travels with a frame because its ID is a member, not because it overlaps the frame. See that page for framework mounting and instance setup.

Create a frame and add members

In Angular, Vue, and React, mount ordinary node data, then use the mounted instance's engine to create a group, set its frame, and add node IDs to it. The renderer shows the frame behind the nodes. Membership is explicit: a node does not become a member merely because it overlaps the frame.

For groups declared with the diagram data, use GroupSpec. The JavaScript and Qwik examples declare the group in their initial specifications; Angular, Vue, and React add it through the mounted engine.

js
import { render } from '@grafloria/element';

const host = document.createElement('div');
host.style.height = '400px';
document.body.append(host);

const nodes = [
  { id: 'ingest', position: { x: 320, y: 160 }, size: { width: 120, height: 60 }, label: 'ingest' },
  { id: 'transform', position: { x: 520, y: 160 }, size: { width: 120, height: 60 }, label: 'transform' },
  { id: 'retry', position: { x: 420, y: 280 }, size: { width: 120, height: 60 }, label: 'retry' },
];
const edges = [
  { id: 'e1', source: 'ingest', target: 'transform' },
  { id: 'e2', source: 'ingest', target: 'retry' },
];
const groups = [
  {
    id: 'pipeline',
    label: 'Pipeline',
    children: ['ingest', 'transform', 'retry'],
    bounds: { x: 290, y: 120, width: 400, height: 240 },
  },
];

render({ nodes, edges, groups }, host);

The examples render three ordinary nodes inside a labelled Pipeline frame, with two edges still connecting them. The frame's coordinates are in diagram world space.

For a nested container, create another group, add its node members, and add that group's ID to the outer group. Call fitToContents() from the inner group outward when the frames need to wrap their contents. Membership remains a model relationship rather than a rule inferred from current node positions.

Group definition options

For groups declared in diagram data instead of added after mount, use GroupSpec. A group spec defines the frame and its initial member node IDs.

OptionTypeDefaultWhat it does
idstring—Identifies the group.
labelstring—Supplies the frame's visible label.
childrenstring[]—Names the node IDs that become members.
bounds{ x: number; y: number; width: number; height: number }—Pins the frame to a world-space rectangle; without it, the frame fits around its children using padding.
paddingnumber20Sets the space between the children and a fitted frame.
labelPlacementGroupLabelPlacement'top-left'Places the frame label.
styleGroupFrameStyle—Sets the frame's style.

What to watch for

  • Set a real height on the canvas wrapper. The canvas fills its parent; an unresolved height leaves no drawing area.
  • Use addToGroup(groupId, entityId) in that order. It returns a promise, so await it before treating membership as complete.
  • A node positioned inside a frame is not necessarily a member. Add it to the group explicitly.
  • Groups and membership are edits made through engine operations; use the engine's history APIs for undo and redo rather than looking for those methods on the instance.

See it running

  • Group frames — visible labelled frames, including a nested frame.
  • Sub-flow — nested group membership and fit-to-contents behavior.

For collapsing and expanding a group, see Collapse and expand groups. For the model behind groups and membership, see The graph model and document.

Was this page helpful?