Skip to content
edmi-ui

Connection

Connection line shown while dragging a new edge.

StackBlitz ↗StackBlitz ↗StackBlitz ↗

Drag from the right handle of Start.

Drag from the right handle of Start.

Drag from the right handle of Start.

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
Terminal window
npx shadcn@latest add @edmi-ui/ai-connection
Terminal window
pnpm dlx shadcn@latest add @edmi-ui/ai-connection
Terminal window
yarn dlx shadcn@latest add @edmi-ui/ai-connection
Terminal window
bunx shadcn@latest add @edmi-ui/ai-connection

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

Terminal window
npx shadcn-vue@latest add @edmi-ui/ai-connection
Terminal window
pnpm dlx shadcn-vue@latest add @edmi-ui/ai-connection
Terminal window
yarn dlx shadcn-vue@latest add @edmi-ui/ai-connection
Terminal window
bunx shadcn-vue@latest add @edmi-ui/ai-connection

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

Terminal window
npx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-connection.json
Terminal window
pnpm dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-connection.json
Terminal window
yarn dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-connection.json
Terminal window
bunx --bun shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-connection.json

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

import { Canvas } from "@/components/ai/canvas";
<div className="h-56 w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border">
<p className="absolute z-10 m-3 text-xs text-muted-foreground">
Drag from the right handle of Start.
</p>
<Canvas
connectionLineComponent={Connection}
edges={[]}
/>
</div>
<script setup lang="ts">
import { Canvas } from "@/components/ai/canvas";
import { Connection } from "@/components/ai/connection";
import { Node, NodeHeader, NodeTitle } from "@/components/ai/node";
</script>
<template>
<div class="relative h-56 w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border">
<p class="absolute z-10 m-3 text-xs text-muted-foreground">Drag from the right handle of Start.</p>
<Canvas :edges="[]">
<template #node-step="{ data }">
<Node :handles="{ target: data.t, source: !data.t }" class="w-40">
<NodeHeader class="border-b-0">
<NodeTitle>{{ data.l }}</NodeTitle>
</NodeHeader>
</Node>
</template>
<template #connection-line="props">
<Connection v-bind="props" />
</template>
</Canvas>
</div>
</template>
<script lang="ts">
import { Canvas } from "$lib/components/ai/canvas";
</script>
<div style="height: 224px" class="relative w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border">
<p class="absolute z-10 m-3 text-xs text-muted-foreground">Drag from the right handle of Start.</p>
<Canvas bind:nodes bind:edges connectionLineComponent={Connection} />
</div>
registry/components/ai/connection.tsx
import type { ConnectionLineComponent } from "@xyflow/react";
const HALF = 0.5;
/** Line drawn while dragging from a handle: ring-colored bezier with an end dot. */
export const Connection: ConnectionLineComponent = ({
fromX,
fromY,
toX,
toY,
}) => (
<g>
<path
className="animated"
d={`M${fromX},${fromY} C ${fromX + (toX - fromX) * HALF},${fromY} ${fromX + (toX - fromX) * HALF},${toY} ${toX},${toY}`}
fill="none"
stroke="var(--ring)"
strokeLinecap="round"
strokeWidth={1.6}
/>
<circle
cx={fromX}
cy={fromY}
fill="var(--card)"
r={4.5}
stroke="var(--ring)"
strokeWidth={1.6}
/>
<circle cx={toX} cy={toY} fill="var(--ring)" r={3} />
</g>
);
registry/components/ai/connection/Connection.vue
<script setup lang="ts">
import type { ConnectionLineProps } from "@vue-flow/core"
import { computed } from "vue"
/** Line drawn while dragging from a handle: ring-colored bezier with an end dot. */
const props = defineProps<ConnectionLineProps>()
const HALF = 0.5
const pathD = computed(() => {
const { sourceX, sourceY, targetX, targetY } = props
const controlX = sourceX + (targetX - sourceX) * HALF
return `M${sourceX},${sourceY} C ${controlX},${sourceY} ${controlX},${targetY} ${targetX},${targetY}`
})
</script>
<template>
<g data-slot="ai-connection">
<path
class="animated"
fill="none"
stroke="var(--ring)"
stroke-linecap="round"
:stroke-width="1.6"
:d="pathD"
/>
<circle :cx="sourceX" :cy="sourceY" fill="var(--card)" :r="4.5" stroke="var(--ring)" :stroke-width="1.6" />
<circle :cx="targetX" :cy="targetY" fill="var(--ring)" :r="3" />
</g>
</template>
registry/components/ai/connection/index.ts
export { default as Connection } from "./Connection.vue";
src/lib/registry/ai/connection/connection.svelte
<script lang="ts">
import { useConnection } from "@xyflow/svelte";
/** Line drawn while dragging from a handle: ring-colored bezier with an end dot. */
const connection = useConnection();
const HALF = 0.5;
const line = $derived.by(() => {
const { from, to, inProgress } = connection.current;
if (!inProgress || !from || !to) return null;
const controlX = from.x + (to.x - from.x) * HALF;
return {
from,
to,
d: `M${from.x},${from.y} C ${controlX},${from.y} ${controlX},${to.y} ${to.x},${to.y}`,
};
});
</script>
{#if line}
<g data-slot="ai-connection">
<path class="animated" d={line.d} fill="none" stroke="var(--ring)" stroke-linecap="round" stroke-width="1.6" />
<circle cx={line.from.x} cy={line.from.y} r="4.5" fill="var(--card)" stroke="var(--ring)" stroke-width="1.6" />
<circle cx={line.to.x} cy={line.to.y} r="3" fill="var(--ring)" />
</g>
{/if}
src/lib/registry/ai/connection/index.ts
import Connection from "./connection.svelte";
export { Connection };
Part Prop Type Default
Connection connectionLineComponent ring-colored bezier with a hollow start and a filled end dot