Skip to content

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/react

For 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.

Reference

Propsnodes, edges, value… (13)

Props

FlowGraph props
PropType
nodesRequiredreadonly FlowNode[]–
edgesRequiredreadonly FlowEdge[]–
valuestring | null

The open step's id (controlled); null for none.

–
defaultValuestring | null

default null

null
onValueChange(id: string | null) => void–
controlsstring

The id of the region an open step's detail shows in, for aria-controls.

–
orientationFlowOrientation | 'auto'

default 'auto'

'auto'
minimapboolean

A small overview of the whole graph while zoomed in.

default true

true
labelstring

The graph's accessible name. Default: the labels' "Flow graph".

–
localestring

Default: the YoujProvider locale.

–
soundboolean

With sound on, opening a step plays select and closing it close.

default true

true
heightnumber | 'auto'

The canvas height in pixels.

default 'auto'

'auto'
fitFloornumber

The 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

Motion tokens
MomentTokens
Runningthe step’s halo breathes and its dot throws a ring; dashes flow along the edges into it, looping until it finishes
duration.deliberate

560ms

560ms
Zoom and fitthe view glides to its new scale, and can be caught mid-way by a drag or a wheel
duration.slowease.standard

340ms · 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" and aria-controls pointing at controls; 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 select and closing it close.
  • Its words come from the labels (flowGraph, flowGraphHint, the flow* states, flowGraphNode, flowGraphAfter, flowGraphThen, flowGraphAttempts, zoomIn, zoomOut, zoomToFit), translated by the language packs.