Flow
A canvas of nodes joined by edges, that you pan, zoom and rearrange.
Use it to show how things are connected and let somebody move them about: the stages of a pipeline, an automation, the parts of a system. Nodes are boxes with your own contents, edges join them, and the canvas is panned and zoomed.
It lays nothing out for you. Every node is given a position, so for a graph whose shape comes from data you need to work the positions out first. For steps in a fixed order with nothing to rearrange, a list of steps is the simpler thing.
Installation
Copy the folder into components/ui, where you can edit it. It needs the cn helper, class-variance-authority, and the theme's info, success and warning colours.
components/ui/flow/
├── Flow.vue
├── FlowBackground.vue … FlowMiniMap.vue
├── context.ts
├── movable.ts
├── flow-paths.ts
└── index.tsUsage
<script setup lang="ts">
import {
Flow,
FlowBackground,
FlowControls,
FlowEdge,
FlowNode,
FlowNodeContent,
FlowNodeDescription,
FlowNodeTitle,
} from "@/components/ui/flow";
</script>
<template>
<Flow fit-view-on-mount>
<FlowBackground />
<FlowNode id="draft" :position="{ x: 40, y: 20 }">
<FlowNodeContent>
<FlowNodeTitle>Draft</FlowNodeTitle>
</FlowNodeContent>
</FlowNode>
<FlowNode id="edit" :position="{ x: 40, y: 150 }">
<FlowNodeContent>
<FlowNodeTitle>Edit</FlowNodeTitle>
<FlowNodeDescription>Two rounds</FlowNodeDescription>
</FlowNodeContent>
</FlowNode>
<FlowEdge from="draft" to="edit" arrow />
<FlowControls />
</Flow>
</template>Composition
<Flow>
<FlowBackground />
<FlowNode id="…" :position="…">
<FlowNodeHeader>
<FlowNodeDescription />
<FlowNodeBadge />
</FlowNodeHeader>
<FlowNodeContent>
<FlowNodeTitle />
<FlowNodeDescription />
</FlowNodeContent>
<FlowHandle />
</FlowNode>
<FlowGroup id="…" :position="…">
<FlowGroupItem>
<FlowNodeContent />
</FlowGroupItem>
</FlowGroup>
<FlowEdge from="…" to="…" />
<FlowControls />
<FlowMiniMap />
</Flow>- FlowBackground: the pattern behind the graph, dots, lines or crosses. It moves and scales with the graph.
- FlowNode: a box on the graph. id is what edges call it and position is where it starts. Fill it with the node parts below, or with anything of your own.
- FlowNodeHeader: a strip across the top of a node, ruled off from the rest, with something at each end: a step number and a FlowNodeBadge.
- FlowNodeContent: the body of a node, carrying the node's padding. Inside a FlowGroupItem it has none, because the item has its own.
- FlowNodeTitle: what the node is.
- FlowNodeDescription: a quieter line about the node. It is smaller inside a FlowGroupItem.
- FlowNodeBadge: a word in a pill for the node's state, tinted with the theme colour named by color. muted is grey, and the default.
- FlowHandle: a dot on a node's edge that a connection can be drawn from or dropped on. Give it an id to join an edge to it by name.
- FlowEdge: a line from one node to another: a curve, a routed line or a straight one, optionally dashed, marching and with an arrowhead.
- FlowGroup: a dashed box with a label, round things that belong together. It is dragged as one and an edge can be joined to it.
- FlowGroupItem: one thing inside a group that is not a node of its own: an icon beside a FlowNodeContent. It moves with the group, and edges cannot join it.
- FlowControls: buttons to zoom, fit everything in view and lock the canvas.
- FlowMiniMap: the whole graph, small, with the part in view marked on it.
Edges that pick their own side
An edge with no from-side, to-side or handle leaves from whichever face of its node is turned towards the other one. Drag one node past another and the edges turn to follow. Name the sides when the direction should not change.
A mind map
bezier edges from one centre, each in a theme colour of its own. With no sides named, a branch can be dragged anywhere round the centre.
Wiring it up
A FlowHandle is somewhere to start a connection. Drag from one to another node and @connect is told which two; the edges are yours to keep. is-valid-connection refuses the ones you do not want, here a second wire between the same two steps.
Named ports
FlowHandle takes an id, a face and an offset along it, so one face can hold two. Join an edge to it as "node.handle", and that end stays on the port however the node is dragged. Use ports where the side means something: here accepted leaves from one and rejected from the other.
Building a graph
The canvas holds no list of nodes or edges. Each is something you render, so adding one is adding to an array in your own state.
Moving nodes from outside
position is where a node starts. Keep the positions in state, update them from @node-drag-end, and pass new ones to move the nodes yourself.
Nodes inside a group
A FlowNode inside a FlowGroup is placed relative to the group and moves with it. Give the group a size, because the nodes do not lay it out. confine stops a node's drag at the group's edge. pinned gives the drag to the group, so the node moves only when the group does.
Groups and a minimap
FlowGroup holds ordinary elements and moves as one. The edges are joined to the groups by their id. FlowMiniMap shows where the view is on the whole graph.
API Reference
Flow
FlowBackground
FlowNode
FlowGroup
FlowNodeBadge
FlowHandle
FlowEdge
FlowControls
FlowMiniMap
Every part also takes the attributes of the element it renders, and a class.
Notes
Size
The canvas is 24rem tall and as wide as its container. Set a height with class.
It is drawn as a bordered, rounded box. Inside a frame that already has an edge, such as a card or a panel, give it the frame's height and take its own edge off: class="h-full rounded-none border-0". The examples on this page do that.
fit-view-on-mount fits the graph once. Where the room for the graph changes a great deal, as between a phone and a desktop, lay the nodes out for each and give the canvas a key that changes with the layout, so it is fitted again.
Positions
position is the node's top left corner on the graph, in pixels at a zoom of 1. The canvas holds a node's position after that: a drag moves it, and node-drag-end reports where it stopped. To move a node yourself, keep its position in state and pass the new one.
fit-view-on-mount zooms and pans so every node is in view once they have been measured. It never zooms in past 1.
Edges
from and to are node ids, or { node, handle } to join a handle by its id. The faces an edge uses are worked out from where the two nodes are, and change as one is dragged past the other; from-side and to-side fix them.
variant is bezier, smoothstep, step or straight. animated sets dashes marching towards the target, and stops for anyone who has asked for reduced motion. color names one of the theme's roles; without it an edge is a quiet grey.
Panning and zooming
Drag the empty canvas to pan. Zoom with a pinch, or with Control or Command and the wheel. The plain wheel is left to the page, so a diagram in a long page does not trap its scroll. FlowControls has buttons for the same things, and a lock that stops all of it.
Keyboard
The canvas and every node are Tab stops. On the canvas the arrow keys pan, plus and minus zoom and 0 fits everything. On a node the arrow keys move it by move-step, four times as far with Shift, Enter presses it and Delete calls the delete listener.
A connection can only be drawn with a pointer. Where joining nodes matters to everyone, give them another way to do it, such as a menu on the node.
Inside a node
A node is a card by default; pass class to change it. Buttons, links and fields inside a node work as usual and do not start a drag. Put data-no-drag on anything else that should not.
Groups
A group's children are ordinary elements, laid out however you like inside it. They are not nodes: an edge is joined to the group, not to something in it.
Where the parts go
Flow sorts its slot as it renders: FlowBackground is drawn under the graph, FlowControls and FlowMiniMap over it, and everything else in the layer that pans and zooms. Put those three straight inside Flow (a v-if or v-for on them is fine), not inside a component of your own, or they will pan with the graph.
Public exports
- Components: Flow, FlowBackground, FlowNode, FlowNodeHeader, FlowNodeContent, FlowNodeTitle, FlowNodeDescription, FlowNodeBadge, FlowHandle, FlowEdge, FlowGroup, FlowGroupItem, FlowControls, FlowMiniMap
- Types: FlowViewport, FlowNodePosition, FlowConnection, FlowEndpoint, FlowEndpointReference, FlowEdgeVariant, FlowColor, FlowCorner, FlowSide, FlowRect, FlowPoint
Accessibility
Keyboard shortcuts and ARIA behavior.
- The canvas is an application named by label, described as "Diagram". Nodes and groups are described as "Node" and "Group", and a selected node has aria-selected.
- Handles, edges, the background and the minimap are hidden from screen readers. The controls are a group of labelled buttons, and the lock button reports aria-pressed.