Workflow

Edge

Customizable edge components for React Flow canvases with animated and temporary states.

The Edge component provides two pre-styled edge types for React Flow canvases: Temporary for dashed temporary connections and Animated for connections with animated indicators.

The Edge component is designed to be used with the Canvas component. See the Workflow demo for a full example.

Installation

npx ai-elements@latest add edge
npx shadcn@latest add @ai-elements/edge
import {  BaseEdge,  type EdgeProps,  getBezierPath,  getSimpleBezierPath,  type InternalNode,  type Node,  Position,  useInternalNode,} from "@xyflow/react";const Temporary = ({  id,  sourceX,  sourceY,  targetX,  targetY,  sourcePosition,  targetPosition,}: EdgeProps) => {  const [edgePath] = getSimpleBezierPath({    sourceX,    sourceY,    sourcePosition,    targetX,    targetY,    targetPosition,  });  return (    <BaseEdge      className="stroke-1 stroke-ring"      id={id}      path={edgePath}      style={{        strokeDasharray: "5, 5",      }}    />  );};const getHandleCoordsByPosition = (  node: InternalNode<Node>,  handlePosition: Position) => {  // Choose the handle type based on position - Left is for target, Right is for source  const handleType = handlePosition === Position.Left ? "target" : "source";  const handle = node.internals.handleBounds?.[handleType]?.find(    (h) => h.position === handlePosition  );  if (!handle) {    return [0, 0];  }  let offsetX = handle.width / 2;  let offsetY = handle.height / 2;  // this is a tiny detail to make the markerEnd of an edge visible.  // The handle position that gets calculated has the origin top-left, so depending which side we are using, we add a little offset  // when the handlePosition is Position.Right for example, we need to add an offset as big as the handle itself in order to get the correct position  switch (handlePosition) {    case Position.Left:      offsetX = 0;      break;    case Position.Right:      offsetX = handle.width;      break;    case Position.Top:      offsetY = 0;      break;    case Position.Bottom:      offsetY = handle.height;      break;    default:      throw new Error(`Invalid handle position: ${handlePosition}`);  }  const x = node.internals.positionAbsolute.x + handle.x + offsetX;  const y = node.internals.positionAbsolute.y + handle.y + offsetY;  return [x, y];};const getEdgeParams = (  source: InternalNode<Node>,  target: InternalNode<Node>) => {  const sourcePos = Position.Right;  const [sx, sy] = getHandleCoordsByPosition(source, sourcePos);  const targetPos = Position.Left;  const [tx, ty] = getHandleCoordsByPosition(target, targetPos);  return {    sx,    sy,    tx,    ty,    sourcePos,    targetPos,  };};const Animated = ({ id, source, target, markerEnd, style }: EdgeProps) => {  const sourceNode = useInternalNode(source);  const targetNode = useInternalNode(target);  if (!(sourceNode && targetNode)) {    return null;  }  const { sx, sy, tx, ty, sourcePos, targetPos } = getEdgeParams(    sourceNode,    targetNode  );  const [edgePath] = getBezierPath({    sourceX: sx,    sourceY: sy,    sourcePosition: sourcePos,    targetX: tx,    targetY: ty,    targetPosition: targetPos,  });  return (    <>      <BaseEdge id={id} markerEnd={markerEnd} path={edgePath} style={style} />      <circle fill="var(--primary)" r="4">        <animateMotion dur="2s" path={edgePath} repeatCount="indefinite" />      </circle>    </>  );};export const Edge = {  Temporary,  Animated,};

Usage

import { Edge } from '@/components/ai-elements/edge';
const edgeTypes = {
  temporary: Edge.Temporary,
  animated: Edge.Animated,
};

<Canvas
  nodes={nodes}
  edges={edges}
  edgeTypes={edgeTypes}
/>

Features

  • Two distinct edge types: Temporary and Animated
  • Temporary edges use dashed lines with ring color
  • Animated edges include a moving circle indicator
  • Automatic handle position calculation
  • Smart offset calculation based on handle type and position
  • Uses Bezier curves for smooth, natural-looking connections
  • Fully compatible with React Flow's edge system
  • Type-safe implementation with TypeScript

Edge Types

Edge.Temporary

A dashed edge style for temporary or preview connections. Uses a simple Bezier path with a dashed stroke pattern.

Edge.Animated

A solid edge with an animated circle that moves along the path. The animation repeats indefinitely with a 2-second duration, providing visual feedback for active connections.

Props

Both edge types accept standard React Flow EdgeProps:

Prop

Type