Custom Edges
Like custom nodes, parts of a custom edge in
Svelte Flow are just Svelte components: that means you can render anything you want
along an edge! This guide shows you how to implement a custom edge with some
additional controls. For a comprehensive reference of props available for custom edges, see the EdgeProps
documentation.
A basic custom edge
An edge isn’t much use to us if it doesn’t render a path between two connected
nodes. These paths are always SVG-based and are typically rendered using the
<BaseEdge />
component. To calculate
the actual SVG path to render, Svelte Flow comes with some handy utility functions:
To kick start our custom edge, we’ll just render a straight path between the source and target.
<script lang="ts">
import { BaseEdge, getStraightPath, type EdgeProps } from '@xyflow/svelte';
let { id, sourceX, sourceY, targetX, targetY }: EdgeProps = $props();
let [edgePath] = $derived(
getStraightPath({
sourceX,
sourceY,
targetX,
targetY,
})
);
</script>
<BaseEdge {id} {path} />
All the props passed to your custom edge component can be found in the API reference
under the EdgeProps
type.
This gives us a straight edge that behaves the same as the default "straight"
edge type. To use it, we also
need to update the edgeTypes
prop on
the <SvelteFlow />
component.
It’s important to define the edgeTypes
object outside of the component or to
use Svelte’s $derived
to prevent unnecessary re-renders. Svelte Flow will
show a warning in the console if you forget to do this.
<script lang="ts">
import { SvelteFlow, type EdgeTypes } from '@xyflow/svelte';
import CustomEdge from './CustomEdge.svelte';
const edgeTypes: EdgeTypes = {
'custom-edge': CustomEdge
};
</script>
<SvelteFlow {edgeTypes} ... />
After defining the edgeTypes
object, we can use our new custom edge by setting
the type
field of an edge to "custom-edge"
.
<script lang="ts">
import {
SvelteFlow,
type Node,
type Edge,
type EdgeTypes,
Background,
} from '@xyflow/svelte';
import CustomEdge from './CustomEdge.svelte';
import '@xyflow/svelte/dist/style.css';
const edgeTypes: EdgeTypes = {
'custom-edge': CustomEdge,
};
let nodes = $state.raw<Node[]>([
{ id: 'a', position: { x: 0, y: 0 }, data: { label: 'Node A' } },
{ id: 'b', position: { x: 0, y: 100 }, data: { label: 'Node B' } },
]);
let edges = $state.raw<Edge[]>([
{
id: 'a->b',
type: 'custom-edge',
source: 'a',
target: 'b',
},
]);
</script>
<SvelteFlow bind:nodes bind:edges {edgeTypes} fitView>
<Background />
</SvelteFlow>
Adding an edge label
One of the more common uses for custom edges is rendering some controls or info along an edge’s path. In Svelte Flow we call that an edge label and unlike the edge path, edge labels can be any Svelte component!
Because Svelte Flows edges are mounted inside a SVG component, we need to escape it’s context to render a custom edge label. For this, we have a handy <EdgeLabel />
component. Aside from a couple of extras, like inheriting the edges z-index, it functions as a portal that mounts the child components in the viewport div.
Let’s add a button to our custom edge that can be used to delete the edge it’s attached to:
<script lang="ts">
import {
BaseEdge,
EdgeLabel,
getStraightPath,
useEdges,
type EdgeProps,
} from '@xyflow/svelte';
let { id, sourceX, sourceY, targetX, targetY }: EdgeProps = $props();
let [edgePath, labelX, labelY] = $derived(
getStraightPath({
sourceX,
sourceY,
targetX,
targetY,
})
);
const edges = useEdges();
</script>
<BaseEdge {id} {path} />
<EdgeLabel x={labelX} y={labelY}>
<button
class="nodrag nopan"
onclick={() => {
edges.update((eds) => eds.filter((edge) => edge.id !== id));
}}
>
delete
</button>
</EdgeLabel>
To make sure our edge labels are interactive and not just for presentation, it is
important to add the nodrag
and nopan
classes to the label to stop mouse events from
controlling the canvas.
Here’s an interactive example with our updated custom edge. Clicking the delete button will remove that edge from the flow. Creating a new edge will use the custom node.
<script lang="ts">
import {
SvelteFlow,
type Node,
type Edge,
type EdgeTypes,
Background,
} from '@xyflow/svelte';
import CustomEdge from './CustomEdge.svelte';
import '@xyflow/svelte/dist/style.css';
const edgeTypes: EdgeTypes = {
'custom-edge': CustomEdge,
};
let nodes = $state.raw<Node[]>([
{ id: 'a', position: { x: 0, y: 0 }, data: { label: 'Node A' } },
{ id: 'b', position: { x: 0, y: 100 }, data: { label: 'Node B' } },
{ id: 'c', position: { x: 0, y: 200 }, data: { label: 'Node C' } },
]);
let edges = $state.raw<Edge[]>([
{ id: 'a->b', type: 'custom-edge', source: 'a', target: 'b' },
{ id: 'b->c', type: 'custom-edge', source: 'b', target: 'c' },
]);
</script>
<SvelteFlow bind:nodes bind:edges {edgeTypes} fitView>
<Background />
</SvelteFlow>
Making Custom SVG Edge Paths
As discussed previously, if you want to make a custom edge in Svelte Flow, you have to use either of the four path creation functions discussed above (e.g getBezierPath
). However if you want to make some other path shape like a Sinusoidal edge or some other edge type then you will have to make the edge path yourself.
The edge path we get from functions like getBezierPath
is just a path string which we pass into the path
prop of the <BaseEdge />
component. It contains the necessary information needed in order to draw that path, like where it should start from, where it should curve, where it should end, etc. A simple straight path string between two points (x1, y1)
to (x2, y2)
would look like:
M x1 y1 L x2 y2
An SVG path is a concatenated list of commands like M
, L
, Q
, etc, along with their values. Some of these commands are listed below, along with their supported values.
M x1 y1
is the Move To command which moves the current point to the x1, y1 coordinate.L x1 y1
is the Line To command which draws a line from the current point to x1, y1 coordinate.Q x1 y1 x2 y2
is the Quadratic Bezier Curve command which draws a bezier curve from the current point to the x2, y2 coordinate. x1, y1 is the control point of the curve which determines the curviness of the curve.
Whenever we want to start a path for our custom edge, we use the M
command to move our current point to sourceX, sourceY
which we get as props in the custom edge component. Then based on the shape we want, we will use other commands like L
(to make lines), Q
(to make curves) and then finally end our path at targetX, targetY
which we get as props in the custom edge component.
If you want to learn more about SVG paths, you can check out SVG-Path-Editor . You can paste any SVG path there and analyze individual path commands via an intuitive UI.
Here is an example with two types of custom edge paths, a Step edge and a Sinusoidal edge. You should look at the Step edge first to get your hands dirty with custom SVG paths since it’s simple, and then look at how the Sinusoidal edge is made. After going through this example, you will have the necessary knowledge to make custom SVG paths for your custom edges.
<script lang="ts">
import {
SvelteFlow,
type Node,
type Edge,
type EdgeTypes,
Background,
} from '@xyflow/svelte';
import StepEdge from './StepEdge.svelte';
import SineEdge from './SineEdge.svelte';
import '@xyflow/svelte/dist/style.css';
const edgeTypes: EdgeTypes = {
steps: StepEdge,
sine: SineEdge,
};
let nodes = $state.raw<Node[]>([
{ id: 'a', position: { x: 0, y: 0 }, data: { label: 'Node A' } },
{ id: 'b', position: { x: 200, y: 100 }, data: { label: 'Node B' } },
{ id: 'c', position: { x: 0, y: 200 }, data: { label: 'Node C' } },
{ id: 'd', position: { x: 200, y: 300 }, data: { label: 'Node D' } },
]);
let edges = $state.raw<Edge[]>([
{ id: 'a->b', type: 'step', source: 'a', target: 'b' },
{ id: 'c->d', type: 'sine', source: 'c', target: 'd' },
]);
</script>
<SvelteFlow bind:nodes bind:edges {edgeTypes} fitView>
<Background />
</SvelteFlow>