Skip to content

Visual Linker ​

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.

Features ​

  • Auto-side port routing — each connection picks which side of a block to enter/exit on its own, resolved from the other endpoint's position; a FixedSide[] narrows that choice to a subset, and a bounded angle lean can pull the exit/entry angle toward the real target direction
  • Three curve types — bezier (configurable curvature, min/max reach, angle lean), smoothstep (orthogonal routing with rounded corners and group-aware branch points for connections sharing a port), and straight
  • Block drag & drop — pointer-driven dragging with an optional drag handle, a px grid snap, and bounds confined to the container, an element, or an inset box; every incident connection tracks a dragged block in real time
  • Typed event API — block:dragstart/drag/dragend, block:mouseenter/mouseleave, connection:click/mouseenter/mouseleave/selectionchange/delete-request, and a per-render layout event carrying every connection's and port's resolved geometry
  • Per-connection styling — color, width, dashed, start/end markers (four built-in shapes or custom SVG, optionally with a direction arrow attached to the shape), and a distinct hover style, all overridable per connection on top of instance-wide defaults
  • Tidy diagrams — smoothstep lines can be routed around other blocks (lines.routing.avoidObstacles) and hop over the lines they cross (lines.jumps); connections sharing a port side can each get their own virtual port (ports.spread)
  • Labels, flow and selection — any number of labels anywhere along a line (library-drawn or your own content), an animated dashed or dotted flow showing direction, and selectable, keyboard-operable, screen-reader-friendly connections that ask the app to delete rather than deleting themselves
  • Scrolling containers — a port scrolled out of a clipping ancestor pins its line to the visible edge (or hides it) instead of dangling over other content
  • One structured configuration — a single VisualLinkerConfig (theme, lines, markers, ports, labels, blocks, interaction) for the engine, the Vue component and the Nuxt module; a connection's style has the same shape as the lines group, and the whole configuration can be changed at runtime
  • Visual states — highlight, hover, selected and focus for lines, markers, ports and labels, each with its own fields: a marker can turn from a dot into a diamond on hover, a line can fade at rest and come to full strength under the pointer; hover and highlight are opt-in (interaction.hover, interaction.highlight)
  • Themes — color tokens written to CSS variables, with lightTheme, darkTheme and defineTheme() for your own; switch one theme for every diagram of a Vue app or Nuxt project in a single assignment
  • Resize & scroll reactivity — every connection recomputes itself when a block or the container resizes, or the page scrolls — no manual event wiring
  • A component, a composable, and a Nuxt module — <VisualLinker> around your own markup (blocks marked with v-vl-block/data-vl-block at any depth, or anywhere on the page with scope="page"), the low-level useVisualLinker() composable, and a Nuxt module with auto-imports, the directives registered, and config-level defaults for curve/port rendering
  • Recipes — complete, tested examples for plain JavaScript, Vue and Nuxt: an ER diagram, a flow editor, field mapping between scrolling lists, an editable diagram with a saved layout, theme switching and a live service map; start with Database Schema (ER Diagram)

Mouse-driven connection creation and an auto-layout mode are still on the roadmap — see the package's own docs/TECH_SPEC.md for the full milestone list. Everything listed above is implemented and tested today.