Edges
The edge shape, the path-type variants the built-in renderer understands, and the animated flag.
#Edge Shape
An edge connects two nodes by their ids. The minimal shape is { id, source, target }; everything else — the curve type, animation, handle pinning — is opt-in. Flow looks up source / target in the node lookup, finds the matching handles, and draws a path between them.
1// An edge is a plain object connecting two node ids.2const edges = [3 { id: "a-b", source: "a", target: "b" },4 // Optional fields:5 // - type : 'default' | 'bezier' | 'straight' | 'smoothstep' | 'step'6 // - animated : true → renders a moving dashed stroke7 // - sourceHandle / targetHandle : pin to a specific handle id8 // - selected : initial selection state9 // - data : arbitrary payload for forward compatibility10]#Default Routing
With no type set, an edge renders as a Bezier curve from the source node's bottom handle to the target node's top handle.
#A single edge
1import { Flow, Background } from "@/components/ui/xyflow"23const nodes = [4 { id: "a", position: { x: 80, y: 30 }, data: { label: "Hello" } },5 { id: "b", position: { x: 280, y: 150 }, data: { label: "World" } },6]7const edges = [8 { id: "a-b", source: "a", target: "b" },9]1011export function MyFlow() {12 return (13 <div className="w-full h-[240px] rounded-lg border bg-background overflow-hidden">14 <Flow nodes={nodes} edges={edges}>15 <Background variant="dots" gap={30} />16 </Flow>17 </div>18 )19}#Edge Variants
The built-in <SimpleEdge> picks a path algorithm from the edge's type string — "default" / "bezier" (curve), "straight" (line), "smoothstep" / "step" (right-angle).
#Four path types side-by-side
1// Each edge picks its path algorithm from `type`.2const edges = [3 { id: "e1", source: "l1", target: "r1" }, // default (bezier)4 { id: "e2", source: "l2", target: "r2", type: "bezier" },5 { id: "e3", source: "l3", target: "r3", type: "smoothstep" },6 { id: "e4", source: "l4", target: "r4", type: "straight" },7]#Animated Edges
Set animated: true on an edge and <SimpleEdge> appends the bf-flow__edge--animated class — a stroke-dasharray keyframe animation that gives a sense of direction or activity. The flag is independent of type, so it composes with any of the path variants.
#Animated stroke
1// Toggle the moving-dash animation per edge.2const edges = [3 { id: "a-b", source: "a", target: "b", animated: true },4 { id: "b-c", source: "b", target: "c", animated: true },5]67<Flow nodes={nodes} edges={edges}>8 <Background variant="dots" gap={30} />9</Flow>#rAF Flow Animation
The CSS keyframe animation above happens entirely inside the browser. When you need the path direction or speed to be reactive — to track a signal — drive the stroke-dashoffset attribute from a requestAnimationFrame loop owned by a createEffect. Toggling the effect off calls cancelAnimationFrame in onCleanup, so the loop never leaks past unmount.
#rAF-driven dashoffset
1"use client"23import { createSignal, createEffect, onCleanup } from "@barefootjs/client"45export function XyflowFlowAnimateDemo() {6 const [animating, setAnimating] = createSignal(false)7 const [offset, setOffset] = createSignal(0)89 createEffect(() => {10 if (!animating()) return11 let frame = 012 let last = performance.now()13 const tick = (now) => {14 const dt = now - last15 last = now16 setOffset((prev) => (prev - dt * 0.04) % 16)17 frame = requestAnimationFrame(tick)18 }19 frame = requestAnimationFrame(tick)20 onCleanup(() => cancelAnimationFrame(frame))21 })2223 return (24 <div>25 <button onClick={() => setAnimating(!animating())}>26 {animating() ? "Stop" : "Animate flow"}27 </button>28 <svg viewBox="0 0 520 180">29 <path30 d="M 40 60 C 140 60 160 120 280 120 S 380 60 480 60"31 fill="none"32 stroke="currentColor"33 stroke-width="3"34 stroke-dasharray="8 8"35 stroke-dashoffset={String(offset())}36 />37 </svg>38 </div>39 )40}