FlowGroupNodeBase
Base class for resizable group nodes. Create container nodes that can organize and group other nodes.
Overview
FlowGroupNodeBase extends FlowNodeBase with resizing capabilities. Group nodes typically appear behind regular nodes and provide visual organization.
Inherits From
Additional Properties
| Property | Type | Default | Description |
|---|---|---|---|
| Width | double | 300 | Node width in pixels |
| Height | double | 300 | Node height in pixels |
Additional Methods
GetNodesInGroupAsync
Gets IDs of nodes currently contained within the group boundaries.
Signature: ValueTask<string[]> GetNodesInGroupAsync()
var containedNodeIds = await groupNode.GetNodesInGroupAsync();
Console.WriteLine($"Group contains {containedNodeIds.Length} nodes");
SetSizeAsync
Sets the size of the group node.
Signature: ValueTask SetSizeAsync(double width, double height)
await groupNode.SetSizeAsync(500, 400);
OnResized
Virtual method called when the node is resized (override to add custom behavior).
Signature: virtual void OnResized(double width, double height)
public override void OnResized(double width, double height)
{
base.OnResized(width, height);
// Custom resize logic
Console.WriteLine($"Resized to {width}x{height}");
}
OnRenderedAsync
Override to set initial size.
Signature: override async ValueTask OnRenderedAsync()
public override async ValueTask OnRenderedAsync()
{
await base.OnRenderedAsync();
await SetSizeAsync(Width, Height);
}
Creating a Group Node
MyGroupNode.razor.cs
using FlowState.Components;
using FlowState.Attributes;
using FlowState.Models.Execution;
namespace MyNamespace;
[FlowNodeMetadata(
Title = "Group",
Category = "Layout",
Icon = "π¦",
Kind = NodeKind.Group // Important: Mark as Group kind
)]
public partial class MyGroupNode : FlowGroupNodeBase
{
protected override void OnInitialized()
{
base.OnInitialized();
Width = 400;
Height = 300;
}
public override void OnResized(double width, double height)
{
base.OnResized(width, height);
// Log resize or update UI
}
public override async ValueTask ExecuteAsync(FlowExecutionContext context)
{
// Group nodes typically don't execute
// But you can add logic if needed
await ValueTask.CompletedTask;
}
}
MyGroupNode.razor
@using FlowState.Components
@inherits FlowGroupNodeBase
<FlowNode>
<div class="group-title">π¦ Group</div>
<FlowResizeHandle />
</FlowNode>
<style>
.group-title {
padding: 8px 12px;
font-size: 13px;
font-weight: 600;
color: rgba(255, 255, 255, 0.7);
background: rgba(255, 255, 255, 0.05);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
</style>
Styling Group Nodes
Group nodes should appear behind regular nodes using CSS z-index:
/* Group nodes behind everything */
.flow-node[kind="Group"] {
z-index: 1 !important;
background: rgba(50, 50, 50, 0.5);
border: 2px dashed rgba(255, 255, 255, 0.3);
backdrop-filter: blur(4px);
}
/* Regular nodes on top */
.flow-node:not([kind="Group"]) {
z-index: 10;
}
/* Edges in between */
.edge {
z-index: 5;
}
Complete Example
GroupNode.razor.cs
using FlowState.Components;
using FlowState.Attributes;
using FlowState.Models.Execution;
[FlowNodeMetadata(
Title = "Container",
Category = "Layout",
Icon = "π",
Description = "Resizable container for organizing nodes",
Kind = NodeKind.Group
)]
public partial class GroupNode : FlowGroupNodeBase
{
protected override void OnInitialized()
{
base.OnInitialized();
Width = 500;
Height = 350;
}
public override void OnResized(double width, double height)
{
base.OnResized(width, height);
StateHasChanged(); // Update UI if displaying size
}
public override async ValueTask ExecuteAsync(FlowExecutionContext context)
{
// Get nodes in this group
var nodes = await GetNodesInGroupAsync();
Console.WriteLine($"Group contains: {string.Join(", ", nodes)}");
await ValueTask.CompletedTask;
}
}
GroupNode.razor
@using FlowState.Components
@inherits FlowGroupNodeBase
<FlowNode>
<div class="group-container">
<div class="group-header">
<span class="group-icon">π</span>
<span class="group-title">Container</span>
<span class="group-size">@WidthΓ@Height</span>
</div>
<FlowResizeHandle />
</div>
</FlowNode>
<style>
.group-container {
width: 100%;
height: 100%;
}
.group-header {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 14px;
background: rgba(255, 255, 255, 0.05);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.group-icon {
font-size: 16px;
}
.group-title {
flex: 1;
font-size: 13px;
font-weight: 600;
color: rgba(255, 255, 255, 0.8);
}
.group-size {
font-size: 11px;
color: rgba(255, 255, 255, 0.5);
font-family: monospace;
}
/* Make group nodes semi-transparent and behind others */
.flow-node[kind="Group"] {
z-index: 1 !important;
background: rgba(30, 30, 40, 0.6);
border: 2px dashed rgba(124, 58, 237, 0.4);
backdrop-filter: blur(4px);
}
.flow-node[kind="Group"]:hover {
border-color: rgba(124, 58, 237, 0.6);
}
</style>
Usage in Graph
// Create a group node
var groupNode = await graph.CreateNodeAsync<GroupNode>(100, 100, []);
// Create regular nodes inside the group area
var node1 = await graph.CreateNodeAsync<MyNode>(150, 150, []);
var node2 = await graph.CreateNodeAsync<MyNode>(250, 150, []);
// Get nodes in the group
var group = graph.GetNodeById(groupNode.Id) as GroupNode;
var containedNodes = await group!.GetNodesInGroupAsync();
Programmatic Resizing
var groupNode = graph.GetNodeById("group-id") as FlowGroupNodeBase;
if (groupNode != null)
{
// Resize to fit content
await groupNode.SetSizeAsync(600, 450);
}
Z-Index Layering
The recommended z-index structure:
/* Layer 1: Group nodes (background) */
.flow-node[kind="Group"] {
z-index: 1 !important;
}
/* Layer 2: Edges */
.edge {
z-index: 5;
}
/* Layer 3: Regular nodes (foreground) */
.flow-node:not([kind="Group"]) {
z-index: 10;
}
/* Layer 4: Selected nodes (always on top) */
.flow-node.selected {
z-index: 100 !important;
}
See Also
- FlowResizeHandle - Resize handle component
- FlowNodeBase - Base node class
- Custom Nodes - Creating custom nodes