Flow Editor styling
The package supplies geometry and interaction styles, while CSS custom properties and custom templates let applications align the editor with their product theme.
Required styles
Flow Editor requires the Foblex theme emitted by the package stylesheet. Import it globally; component-scoped imports do not reliably reach Foblex's generated SVG and overlay elements.
styles.css
/* Add once to the application global stylesheet. */
@import '@tailng-ui/flow/styles.css';Host sizing
The editor defaults to 36rem high with a 24rem minimum. Override the host height for full-screen builders, drawers, or compact embedded monitors. A nonzero height is mandatory for Foblex geometry.
agent-builder.component.css
tng-flow-editor.agent-builder {
display: block;
height: min(70vh, 48rem);
min-height: 30rem;
}CSS custom properties
Defaults resolve through TailNG semantic tokens, so runtime preset and light/dark mode changes update the canvas, nodes, connections, and controls automatically. Override these properties only when an individual editor needs additional product-specific treatment.
| Property group | Properties |
|---|---|
| Canvas | --tng-flow-background, --tng-flow-border-color, --tng-flow-border-radius, --tng-flow-grid-color, --tng-flow-grid-dot-radius |
| Selection and validation | --tng-flow-selection-color, --tng-flow-node-error-border, --tng-flow-node-warning-border, --tng-flow-node-info-border |
| Smart guides | --tng-flow-smart-guide-color, --tng-flow-smart-guide-spacing-fill, --tng-flow-smart-guide-spacing-border |
| Ports | --tng-flow-port-border, --tng-flow-port-background, --tng-flow-port-label-color, --tng-flow-port-error-color |
| Connections and badges | --tng-flow-connection-color, --tng-flow-connection-error-color, --tng-flow-connection-active-color, --tng-flow-connection-success-color, --tng-flow-connection-disabled-color, --tng-flow-connection-width, --tng-flow-connection-selected-width, --tng-flow-connection-hit-width, --tng-flow-connection-label-max-width, --tng-flow-connection-label-background, --tng-flow-connection-label-color, --tng-flow-connection-label-border, --tng-flow-validation-badge-size |
| Connection motion | --tng-flow-connection-flow-duration-slow, --tng-flow-connection-flow-duration-normal, --tng-flow-connection-flow-duration-fast, --tng-flow-connection-motion-reduced-width, --tng-flow-connection-dash-size, --tng-flow-connection-dash-gap |
| Drag handle | --tng-flow-handle-border, --tng-flow-handle-background, --tng-flow-handle-color |
| Controls | --tng-flow-controls-border, --tng-flow-controls-background |
| Minimap | --tng-flow-minimap-background, --tng-flow-minimap-border, --tng-flow-minimap-shadow, --tng-flow-minimap-node, --tng-flow-minimap-node-selected, --tng-flow-minimap-node-disabled, --tng-flow-minimap-node-error, --tng-flow-minimap-viewport-border, --tng-flow-minimap-viewport-background |
| Status badge | --tng-flow-status-bg, --tng-flow-status-fg |
TailNG semantic token mapping
tng-flow-editor.agent-builder {
--tng-flow-background: var(--tng-semantic-background-canvas);
--tng-flow-border-color: var(--tng-semantic-border-subtle);
--tng-flow-border-radius: 1rem;
--tng-flow-grid-color: color-mix(
in srgb,
var(--tng-semantic-foreground-secondary) 22%,
transparent
);
--tng-flow-grid-dot-radius: 1px;
--tng-flow-smart-guide-color: var(--tng-semantic-accent-brand);
--tng-flow-smart-guide-spacing-fill: color-mix(
in srgb,
var(--tng-semantic-accent-brand) 10%,
transparent
);
--tng-flow-smart-guide-spacing-border: color-mix(
in srgb,
var(--tng-semantic-accent-brand) 30%,
transparent
);
--tng-flow-selection-color: var(--tng-semantic-accent-brand);
--tng-flow-node-error-border: var(--tng-semantic-accent-danger);
--tng-flow-node-warning-border: var(--tng-semantic-accent-warning);
--tng-flow-node-info-border: var(--tng-semantic-accent-info);
--tng-flow-port-error-color: var(--tng-semantic-accent-danger);
--tng-flow-connection-color: var(--tng-semantic-foreground-secondary);
--tng-flow-connection-error-color: var(--tng-semantic-accent-danger);
--tng-flow-connection-width: 2px;
--tng-flow-connection-selected-width: 3px;
--tng-flow-connection-hit-width: 14px;
--tng-flow-validation-badge-size: 1.25rem;
--tng-flow-port-border: var(--tng-semantic-foreground-secondary);
--tng-flow-port-background: var(--tng-semantic-background-surface);
--tng-flow-port-label-color: var(--tng-semantic-foreground-secondary);
--tng-flow-connection-label-max-width: 12rem;
--tng-flow-connection-label-background: var(--tng-semantic-background-surface);
--tng-flow-connection-label-color: var(--tng-semantic-foreground-secondary);
--tng-flow-connection-label-border: var(--tng-semantic-border-default);
--tng-flow-connection-dash-size: 8;
--tng-flow-connection-dash-gap: 6;
--tng-flow-connection-flow-duration-slow: 1.8s;
--tng-flow-connection-flow-duration-normal: 1s;
--tng-flow-connection-flow-duration-fast: 0.55s;
--tng-flow-connection-motion-reduced-width: 3px;
--tng-flow-controls-background: var(--tng-semantic-background-surface);
--tng-flow-controls-border: var(--tng-semantic-border-subtle);
--tng-flow-minimap-background: var(--tng-semantic-background-surface);
--tng-flow-minimap-border: var(--tng-semantic-border-default);
--tng-flow-minimap-node-selected: var(--tng-semantic-accent-brand);
--tng-flow-minimap-node-error: var(--tng-semantic-accent-danger);
}Connection motion
Use the typed presentation API to activate connection motion. Duration custom properties can tune the three speeds without exposing Foblex class names as public TailNG styling hooks. Under prefers-reduced-motion: reduce, Flow Editor removes the animation and dash pattern while keeping the path visibly emphasized.
Custom node content
Consumer templates are compiled in the application's context, so they can compose any TailNG or application component. Keep the editor-owned node host and ports intact by customizing only the projected body.
Custom tool node
<tng-flow-editor [nodes]="nodes()" [connections]="connections()">
<ng-template tngFlowNode="tool" let-node let-view="view" let-issues="issues">
<tng-card
class="tool-node"
[interactive]="true"
[tone]="view.status === 'failed' ? 'danger' : 'neutral'"
[attr.data-selected]="view.selected ? '' : null"
[attr.data-validation]="view.validationSeverity"
>
<strong>{{ node.name }}</strong>
<p>{{ node.data.summary }}</p>
<span>{{ issues.length }} issue(s)</span>
</tng-card>
</ng-template>
</tng-flow-editor>