Flux 2.0

Component

Flow diagram

Steps and the connections between them on a pannable canvas, for automations and process maps.

Plain-text source, for agents and clipboard use: /components/source/flow.txt

When to use it

Shows how steps connect: a trigger, the conditions it passes through and the actions at the end. Nodes are buttons laid out on a grid of flow units, edges are curves with arrowheads in one SVG, and branch labels sit on their edges. Selecting a node highlights the edges that touch it. The canvas scrolls inside its frame, and a minimap shows where the viewport sits.

Not this
Not for a strictly linear sequence; use the Stepper or the Timeline. Not for an organisation chart or a hierarchy; use a tree or nested list. Not for editing a diagram freely; that needs a canvas library, which this component styles but does not replace.

Examples

Automation

Final documents go out 30 days before departure. Select a node to see its connections; scroll the canvas and watch the minimap.

html
<div class="flux-flow" data-flux-flow>
  <div class="flux-flow__viewport" role="region" aria-label="Automation: final documents" tabindex="0">
    <div class="flux-flow__canvas" style="--flux-cols: 66; --flux-rows: 30">
      <svg class="flux-flow__edges" viewBox="0 0 66 30" aria-hidden="true">
        <defs>
          <pattern id="flow-grid" width="1" height="1" patternUnits="userSpaceOnUse"><circle class="flux-flow__dot" cx="0.5" cy="0.5" r="0.06" /></pattern>
          <marker id="flow-arrow" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="0.6" markerHeight="0.6" markerUnits="userSpaceOnUse" orient="auto"><path class="flux-flow__arrow" d="M0 0L10 5L0 10z" /></marker>
          <marker id="flow-arrow-active" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="0.6" markerHeight="0.6" markerUnits="userSpaceOnUse" orient="auto"><path class="flux-flow__arrow flux-flow__arrow--active" d="M0 0L10 5L0 10z" /></marker>
        </defs>
        <rect width="66" height="30" fill="url(#flow-grid)" />
        <path class="flux-flow__edge" data-from="confirmed" data-to="check" d="M14 14.5 C16 14.5 16 14.5 18 14.5" marker-end="url(#flow-arrow)" />
        <path class="flux-flow__edge" data-from="check" data-to="documents" d="M30 14.5 C32.5 14.5 32.5 7.5 35 7.5" marker-end="url(#flow-arrow)" />
        <path class="flux-flow__edge" data-from="check" data-to="wait" d="M30 14.5 C32.5 14.5 32.5 21.5 35 21.5" marker-end="url(#flow-arrow)" />
        <path class="flux-flow__edge" data-from="wait" data-to="documents" d="M41 19 L41 10" marker-end="url(#flow-arrow)" />
        <path class="flux-flow__edge" data-from="documents" data-to="guide" d="M47 7.5 C49.5 7.5 49.5 7.5 52 7.5" marker-end="url(#flow-arrow)" />
      </svg>
      <span class="flux-flow__label" style="--flux-x: 32.5; --flux-y: 11" aria-hidden="true">Yes</span>
      <span class="flux-flow__label" style="--flux-x: 32.5; --flux-y: 18" aria-hidden="true">No</span>
      <ol class="flux-flow__nodes">
        <li><button class="flux-flow__node" type="button" data-node="confirmed" style="--flux-x: 2; --flux-y: 12; --flux-w: 12; --flux-h: 5" aria-pressed="false"><span class="flux-flow__node-type">Trigger</span><span class="flux-flow__node-title">Booking confirmed</span><span class="flux-visually-hidden">. Then: Departs within 30 days</span></button></li>
        <li><button class="flux-flow__node" type="button" data-node="check" style="--flux-x: 18; --flux-y: 12; --flux-w: 12; --flux-h: 5" aria-pressed="false"><span class="flux-flow__node-type">Condition</span><span class="flux-flow__node-title">Departs within 30 days</span><span class="flux-visually-hidden">. Yes: Send final documents. No: Until 30 days before departure</span></button></li>
        <li><button class="flux-flow__node" type="button" data-node="documents" style="--flux-x: 35; --flux-y: 5; --flux-w: 12; --flux-h: 5" aria-pressed="false"><span class="flux-flow__node-type">Action</span><span class="flux-flow__node-title">Send final documents</span><span class="flux-visually-hidden">. Then: Assign tour guide</span></button></li>
        <li><button class="flux-flow__node" type="button" data-node="wait" style="--flux-x: 35; --flux-y: 19; --flux-w: 12; --flux-h: 5" aria-pressed="false"><span class="flux-flow__node-type">Wait</span><span class="flux-flow__node-title">Until 30 days before departure</span><span class="flux-visually-hidden">. Then: Send final documents</span></button></li>
        <li><button class="flux-flow__node" type="button" data-node="guide" style="--flux-x: 52; --flux-y: 5; --flux-w: 12; --flux-h: 5" aria-pressed="false"><span class="flux-flow__node-type">Action</span><span class="flux-flow__node-title">Assign tour guide</span></button></li>
      </ol>
    </div>
  </div>
  <div class="flux-flow__minimap" aria-hidden="true">
    <svg viewBox="0 0 66 30">
      <rect class="flux-flow__minimap-node" x="2" y="12" width="12" height="5" rx="0.5" />
      <rect class="flux-flow__minimap-node" x="18" y="12" width="12" height="5" rx="0.5" />
      <rect class="flux-flow__minimap-node" x="35" y="5" width="12" height="5" rx="0.5" />
      <rect class="flux-flow__minimap-node" x="35" y="19" width="12" height="5" rx="0.5" />
      <rect class="flux-flow__minimap-node" x="52" y="5" width="12" height="5" rx="0.5" />
      <rect class="flux-flow__minimap-viewport" x="0" y="0" width="66" height="30" />
    </svg>
  </div>
</div>

Anatomy

PartDescription
FrameA bordered layer-01 container with a scrolling viewport.
CanvasSized in flow units with --flux-cols and --flux-rows, under a dot grid.
NodeA button positioned by --flux-x, --flux-y, --flux-w and --flux-h, with a mono type label and a title. Selected nodes take surface-selected and a brand border.
EdgeAn SVG path in border-strong with an arrowhead, in the same units as the nodes. Edges touching the selected node turn brand.
Edge labelA mono label at the midpoint of a branch, on the canvas colour so the line breaks behind it.
MinimapThe nodes in miniature and a frame for the visible area, in the bottom corner. Clicking it scrolls the canvas.

API

NameKindDescription
flux-flowclassThe frame. data-flux-flow handles selection, the edge highlight and the minimap.
flux-flow__viewportclassThe scroll container. Give it role="region", a name and tabindex="0".
flux-flow__canvasclassSized by inline --flux-cols and --flux-rows in flow units.
flux-flow__edges | __edge | __arrowclassThe SVG, with viewBox="0 0 cols rows", its paths and arrowhead markers. data-from and data-to name the nodes an edge joins.
flux-flow__labelclassAn edge label, positioned with unitless --flux-x and --flux-y.
flux-flow__nodes | __node | __node-type | __node-titleclassThe ordered list of node buttons, each with data-node, aria-pressed and inline unitless --flux-x, --flux-y, --flux-w and --flux-h.
flux-flow__minimap | __minimap-node | __minimap-viewportclassThe overview, drawn in the same units.
flux-flow-selectattributeEvent dispatched on the frame when the selection changes. detail.node is the button, or null.

States

StateTreatment
Defaultlayer-01 node with a border-strong hairline.
Selectedsurface-selected, brand border, and brand edges in and out.
ScrolledThe minimap frame follows the visible area.

Keyboard

KeysAction
TabMoves through the nodes in list order, which is the order of the process.
Enter / SpaceSelects the node, or clears the selection if it was selected.
Arrow keysScroll the canvas when the viewport has focus.

Accessibility

  • Edges are invisible to a screen reader, so each node carries hidden text naming what comes next: “Yes: Send final documents. No: Until 30 days before departure.” Write node titles so they read on their own after a branch label.
  • List nodes in the order the process runs, not the order they were drawn.
  • The minimap is hidden from assistive technology; the viewport scrolls with the keyboard.
  • Selected state is a border and a ground change, and aria-pressed says it too.

Tokens

The tier-3 and tier-2 tokens this component binds to. Change the token, not the component.

  • --flux-flow-unit | -height | -bg | -border | -grid
  • --flux-flow-node-bg | -node-border | -node-padding | -node-type
  • --flux-flow-node-selected-bg | -node-selected-border
  • --flux-flow-edge | -edge-active | -edge-width | -label-bg
  • --flux-flow-minimap-width | -minimap-bg | -minimap-node | -minimap-viewport

Do and don’t

Do

  • Lay the flow out left to right, branching up and down.
  • Label every branch out of a condition.

Don’t

  • Do not colour nodes by type; the type label says it. Colour is for the selection.
  • Do not cross edges when moving a node would avoid it.