Skip to content

Visual Linker

v0.4.3UI ComponentsVanilla JSVueNuxt

Draws smart, auto-routed SVG connector lines between DOM blocks you already control — for vanilla JS, Vue 3, and Nuxt. You own the block markup and position; this only measures it and draws the lines.

Visual Linker
Get started →
npm install @macrulez/visual-linker-core
01 — Purpose

When you'd reach for this

Connections between arbitrary interface blocks — a process map, an entity diagram, a dependency visualization — usually mean either a heavyweight diagramming engine with its own node system, or hand-rolled SVG path drawing on top of ordinary markup, with coordinates recomputed by hand on every resize and scroll. Visual Linker handles just that mechanics, leaving the blocks' markup and positioning entirely yours.

A process flowchart built from ordinary cards

Approval stages, a sales funnel, a request-processing pipeline — each stage is already just a regular component. Lines between the cards route themselves automatically, picking an entry/exit side and avoiding the blocks themselves, and recompute on their own when the window resizes or the container scrolls.

A dependency diagram between interface nodes

Relationships between entities — system components, scenario steps, graph nodes — need showing without writing a custom SVG path renderer. Two curve types (bezier, and an orthogonal smoothstep aware of shared branch points) cover both soft and strictly rectangular layouts.

An interactive diagram with draggable blocks

The user drags blocks around with the mouse, and the lines between them need to follow in real time while still picking their connection side automatically. Block drag & drop, hover and click on the connection line itself, are already part of the API, with a typed event surface.

A consistent connection style across the product's design system

Each line can have its own color, width, dash pattern, start/end markers (built-in shapes or custom SVG), and a distinct hover style — connections are styled with the same level of detail as the blocks themselves.

02 — Features

At a glance

Automatic connection-side routing

Automatic connection-side routing

Every line picks which side of a block to enter and exit on its own, with an optional restriction on the allowed sides and a bounded angle lean toward the real target direction — instead of manually assigning ports to each connection.

Bezier and orthogonal smoothstep curves

Bezier and orthogonal smoothstep curves

Smooth curves with configurable curvature, reach, and angle — or strictly orthogonal routing with branch points that stay aware of connections sharing the same port, for clean rectangular diagrams.

Block drag & drop and connection events

Block drag & drop and connection events

Blocks can be dragged around with the mouse, and lines follow them on their own. Hover and click on a connection are exposed through a typed event API — no manual cursor-coordinate or path-geometry handling.

Per-connection styling

Per-connection styling

Color, width, dash pattern, start and end markers — built-in shapes or custom SVG — and a distinct hover style, all set individually per line.

Resize and scroll reactivity out of the box

Resize and scroll reactivity out of the box

Lines recompute themselves when a block's size changes, the window resizes, or the container scrolls — no manual event wiring in application code.

A component, a composable, and a Nuxt module

A component, a composable, and a Nuxt module

A framework-agnostic engine with a Vue 3 adapter — the <VisualLinker> component around your own markup and the useVisualLinker() composable — plus a Nuxt module with auto-imports and config-level defaults for curve/port rendering.

03 — Quick example

See how it works

An auto-routed line between two blocks

createVisualLinker(container) measures the blocks you hand it via setBlocks() and draws the SVG path between them — no manual geometry, no Vue required.

basic.ts
import { createVisualLinker } from '@macrulez/visual-linker-core'

const container = document.querySelector('#diagram') as HTMLElement
const linker = createVisualLinker(container)

linker.setBlocks([
  { id: 'a', el: document.querySelector('#block-a') as HTMLElement },
  { id: 'b', el: document.querySelector('#block-b') as HTMLElement },
])
linker.setConnections([{ id: 'a-b', from: { blockId: 'a' }, to: { blockId: 'b' } }])

Orthogonal routing and an arrowhead

A connection's style has the same shape as the lines group of the configuration: the curve type, a marker, and a look for every state — here a thicker line and a bigger arrowhead on hover.

styling.ts
linker.setConnections([
  {
    id: 'a-b',
    from: { blockId: 'a' },
    to: { blockId: 'b' },
    style: {
      curve: 'smoothstep',
      color: '#6366f1',
      hover: { width: 3 },
      markers: { end: { shape: 'arrow', hover: { size: 10 } } },
    },
  },
])