Flow Graph
Show the steps of a run or a pipeline as a graph that lays itself out, with each step’s state.
import { FlowEdge, FlowGraph, FlowLayout, FlowLayoutNode, FlowNode } from '@youj/react'
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use a flow graph when steps depend on each other and some run side by side: an agent's tool calls, a data pipeline, a build, a media job. You pass the steps and the edges between them, and it lays them out itself in layers that read in the flow direction: each step one layer past the furthest step it waits on, ordered to keep edges from crossing, and placed near the steps it joins. Steps are mono cards on a dot grid, joined port to port by curves, each showing its state: queued, running (a soft pulse, with dashes flowing along the edges into it), succeeded, failed, retried (with its attempts) or skipped (dashed, like its edges). Picking a step opens it, so the graph can drive a detail panel beside or under it. For a straight line of stages, use a Stage Rail.
import { FlowGraph } from '@youj/react'
<FlowGraph
nodes={[
{ id: 'fetch', label: 'git.log', kind: 'tool', status: 'ok', meta: '1.2 s' },
{ id: 'group', label: 'changes.group', kind: 'llm', status: 'running', meta: '4.8 s' },
{ id: 'draft', label: 'notes.draft', kind: 'llm', status: 'queued' },
]}
edges={[
{ from: 'fetch', to: 'group' },
{ from: 'group', to: 'draft' },
]}
value={open}
onValueChange={setOpen}
controls="step-detail"
/>meta is one figure beside the kind, already formatted ("1.2 s", "404"), and it's spoken after the state. A retried step shows its attempts. Cards are sized to their names so nothing truncates, and the edges of a step that skips a layer are routed around the steps in between. A cycle's closing edge is left out of the layout. layoutFlowGraph(nodes, edges, orientation) returns the same layout for drawing your own.
Description
An image-processing pipeline from upload to CDN, with step statuses and a line of detail for the step you open.
The graph opens fitted to its canvas, but never below fitFloor (85%), so step names stay legible; a wider graph opens at the start of its flow and pans instead of shrinking. The canvas grows to the graph's height (height="auto", from 200 to 640px), or takes a fixed height. Drag the canvas or use the wheel to pan, zoom with Ctrl or ⌘ and the wheel (or a pinch), the corner buttons or + and −, and press 0 to fit again. A minimap shows where you are while the graph overflows (minimap={false} hides it).
orientation="auto" (the default) lays the graph out left to right, right to left under RTL, and top to bottom when the canvas is narrower than 34rem. Pass horizontal or vertical to fix it.
Code
flow-graph-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propsnodes, edges, value… (13)
Props
| Prop | Type | |
|---|---|---|
nodesRequired | readonly FlowNode[] | – |
edgesRequired | readonly FlowEdge[] | – |
value | string | nullThe open step's id (controlled); | – |
defaultValue | string | nulldefault null | null |
onValueChange | (id: string | null) => void | – |
controls | stringThe id of the region an open step's detail shows in, for | – |
orientation | FlowOrientation | 'auto'default 'auto' | 'auto' |
minimap | booleanA small overview of the whole graph while zoomed in. default true | true |
label | stringThe graph's accessible name. Default: the labels' "Flow graph". | – |
locale | stringDefault: the YoujProvider locale. | – |
sound | booleanWith sound on, opening a step plays default true | true |
height | number | 'auto'The canvas height in pixels. default 'auto' | 'auto' |
fitFloor | numberThe least the view zooms out to fit, so step names stay legible; a wider graph pans instead. default FIT_FLOOR | FIT_FLOOR |
Other props pass through: extends ComponentProps<'div'>. | ||
StylingParts and data attributes
Styling
Parts: flow-graph (with data-orientation), flow-graph-viewport (with data-dragging), flow-graph-world, flow-graph-edges, flow-graph-edge (with data-state running, done, pending, error or skipped, and data-active), flow-graph-nodes, flow-graph-node (with data-status and data-open), flow-graph-pulse, flow-graph-port (with data-side), flow-graph-node-status, flow-graph-node-name, flow-graph-node-kind, flow-graph-node-meta, flow-graph-node-attempts, flow-graph-fade, flow-graph-minimap, flow-graph-controls and flow-graph-zoom. The kinds take the theme's label voice; in Bezel they're mono capital eyebrows and the figures are mono.
MotionRunning, zoom and fit, pan · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Runningthe step’s halo breathes and its dot throws a ring; dashes flow along the edges into it, looping until it finishes | duration.deliberate560ms | 560ms | |
| Zoom and fitthe view glides to its new scale, and can be caught mid-way by a drag or a wheel | duration.slowease.standard340ms · cubic-bezier(0.2, 0, 0, 1) | 340mscubic-bezier(0.2, 0, 0, 1) | |
| Panthe view follows the pointer and the wheel, never eased | no token |
Reduced motion
Nothing breathes or flows: a running edge stays dashed in the accent, and zoom and fit land in place.
Reduced motion
The running step holds still and its edges stop flowing (they stay dashed in the accent), and zoom and fit land at once. Panning is unchanged, since it never animates.
AccessibilityKeyboard, ARIA
Accessibility
- The canvas is a group named by
label(default "Flow graph"), described by a hint that explains the keys. The steps are buttons in one list and one tab stop: the running step, the open one, or the first. - Arrow keys along the flow follow the edges to the next or previous step (the nearest one, or back the way you came), the cross arrows move within a layer, and Home and End go to the first and last step. They're mirrored under RTL and turn with the orientation.
- Each step is named by its name, state and figure ("changes.group, Running, 4.8 s") and described by what it follows and leads to ("After git.log. Then notes.draft"). An open step has
aria-expanded="true"andaria-controlspointing atcontrols; Escape closes it. - The state is always a word as well as a color and a dot shape. With sound on, opening a step plays
selectand closing itclose. - Its words come from the labels (
flowGraph,flowGraphHint, theflow*states,flowGraphNode,flowGraphAfter,flowGraphThen,flowGraphAttempts,zoomIn,zoomOut,zoomToFit), translated by the language packs.