Skip to content

Visual Linker ​

0.2.0 ​

2026-09-30

  • Breaking (Vue): <VisualLinker> no longer renders a wrapper <div class="vl-block"> per block around a #block-<id> slot. It now wraps your own markup in its default slot, and blocks are discovered in it at any depth, inside any wrapper components. Migrate by moving the slot content into the default slot and marking each block element with v-vl-block="id" (or data-vl-block="id"):

    vue
    <!-- 0.1.x -->
    <VisualLinker :blocks="blocks" :connections="connections">
      <template v-for="b in blocks" #[`block-${b.id}`]="{}" :key="b.id">
        <MyCard :data="b" />
      </template>
    </VisualLinker>
    
    <!-- 0.2.0 -->
    <VisualLinker :connections="connections">
      <MyCard v-for="b in blocks" :key="b.id" v-vl-block="b.id" :data="b" />
    </VisualLinker>
  • Breaking (Vue): the blocks prop is now optional. An entry can register an element directly through a new el field (a template ref, getter, element, or CSS selector), or — without el — only add config (ports, drag options) to a block already marked in the template.

  • New (Vue): v-vl-block / v-vl-port directives, exported as vVlBlock / vVlPort. A port attaches to the nearest block around it, or to the one named by its block option.

  • New (Vue): plain data-vl-* attributes as a JavaScript-free way to mark blocks and ports (data-vl-block, data-vl-draggable, data-vl-drag-handle, data-vl-drag-bounds, data-vl-port, data-vl-port-block, data-vl-side, data-vl-offset, data-vl-anchor, data-vl-linker); the names are exported as VL_ATTR.

  • New (Vue): live discovery — blocks and ports added, removed, or re-marked after mount (v-if, v-for, third-party markup) are picked up automatically.

  • New (Vue): scope prop — 'container' (default) or 'page', which links elements anywhere in the document and draws in a position: fixed layer teleported to <body>.

  • New (Vue): name prop plus the directives' linker option / data-vl-linker attribute, to assign an element to a specific <VisualLinker>; zIndex prop for the drawing layer. Other attributes passed to <VisualLinker> now land on its root element.

  • New (Vue): VisualLinkerPlugin — app.use() registers <VisualLinker> and both directives globally. VisualLinkerScope, BlockDirectiveOptions, BlockDirectiveValue, PortDirectiveOptions, PortDirectiveValue, RefFriendlyDragBounds and RefFriendlyElement types are exported too.

  • Changed (Vue): the drawing layer is rendered only client-side after mount, keeping the server render identical to the hydration pass.

  • New (Nuxt): v-vl-block / v-vl-port are registered by a universal plugin — on the server too, so the data-vl-* attributes are already in the server-rendered HTML.

  • New (core): MarkerConfig.arrow — true or { color?, gap? } (new MarkerArrowConfig type) draws an arrowhead right before a circle/square/diamond marker, its tip stopping exactly on the shape's outer edge, outline included. A marker carrying an arrow always uses orient: 'auto'.

  • Changed (core): while a connection is highlighted it's painted above its siblings, and other connections ending on the same point hide their marker there, so resting-size markers no longer overlap the highlighted one.

  • Fixed (core): a connection with an explicit style.width lost its hover/highlight width bump — the explicit inline width outranked the CSS rule. The bump is now applied inline too.

  • Changed (core): dragging moves a block through the standalone CSS translate property instead of transform, so it composes with a transform the block already has instead of overwriting it.