Skip to content

Visual Linker ​

0.4.3 ​

2026-10-02

  • Changed (default behavior): hover and highlight are now opt-in. A line used to react to the pointer in every diagram: it took the hover state with a width bump, showed a pointer cursor over its click area, and hovering a block lit up its connections. Now none of that happens until you turn it on, so a diagram that is only looked at stays still. The pointer cursor appears on a line only when hover is on for it or when it is selectable. To get the previous behavior, set interaction: { hover: true, highlight: true }.
  • New: interaction.hover and interaction.highlight. Two independent flags, both false by default. hover is the pointer over a line, highlight is the pointer over a block lighting up its connections. See Visual States.
  • New: hoverable on a connection and highlightable on a block. Each turns its mode on or off for one entity, and the local value wins over the global one. highlightable is also an option of v-vl-block, a field of the blocks prop and the data-vl-highlightable attribute.
  • Unchanged: the events connection:mouseenter, connection:mouseleave, connection:click, block:mouseenter and block:mouseleave fire as before, and the selected and focus states, selection and keyboard operation do not depend on the new flags. A hover or highlight bucket does nothing while its mode is off. Both flags can be changed with setConfig.

0.4.2 ​

2026-10-02

  • A port anchored to a block is no longer pinned by a clipping wrapper inside that block. For a port with anchorBlockId or anchorEl, the point is drawn on the border of the anchor, but whether it is clipped was decided by that point. A row inside an element with overflow: hidden — a rounded segmented control, a card — inside a padded block, anchored to the block's bottom border, has its point below the wrapper, so its line was pulled up to the wrapper's edge and lost its marker and port dot. Whether such a port is clipped is now decided by its own element: a row that is visible keeps its point on the anchor's border, and a row that has scrolled out of view is pinned as before. Ports without an anchor are unchanged. See Scrolling Containers.

0.4.1 ​

2026-10-02

  • Strings are accepted wherever an enum was. The types of lines.curve, a marker's shape and orient, and a port's side were unions of enum members, so TypeScript rejected curve: 'straight' or shape: 'arrow' with Type '"straight"' is not assignable to type 'ConnectionCurve', although both worked at runtime. They are now the plain string unions ('bezier' | 'straight' | 'smoothstep', 'circle' | 'square' | 'diamond' | 'arrow', 'top' | 'right' | 'bottom' | 'left', 'auto' | 'fixed') and still accept the enum members, so existing code keeps compiling. VLConnectionCurveEnum, VLMarkerShapeEnum, VLFixedSideEnum and VLOrientEnum are still exported. See Configuration.

0.4.0 ​

2026-10-02

  • Breaking (all packages): the flat VisualLinkerOptions is replaced by one structured VisualLinkerConfig, grouped by what it styles: theme, lines, markers, ports, labels, blocks and interaction. Every defaultXxx option is gone; each setting has a place in a group. A connection's style has the same shape as the lines group, plus markers: { start, end }. See Configuration. The old names map to the new ones like this:

    0.3.x0.4.0
    defaultCurvelines.curve
    defaultCurvature, defaultCurveMinReach, defaultCurveMaxReach, defaultCurveAngleBlend, defaultCurveAngleMaxOffsetlines.bezier.curvature, minReach, maxReach, angleBlend, angleMaxOffset
    defaultCornerRadius, defaultMaxTrunkReachlines.smoothstep.cornerRadius, lines.smoothstep.maxTrunkReach
    avoidObstacles, obstaclePaddinglines.routing.avoidObstacles, lines.routing.padding
    jumps, defaultAnimatedlines.jumps, lines.animated
    showPortsports.show
    defaultPortRadius, defaultPortColor, defaultPortStrokeColor, defaultPortStrokeWidthports.radius, ports.fill, ports.stroke, ports.strokeWidth
    defaultPortSpreadports.spread
    defaultCircleMarkerSize, defaultSquareMarkerSize, defaultDiamondMarkerSize, defaultArrowMarkerSizemarkers.sizes.circle, square, diamond, arrow
    draggable, dragGridSize, dragBoundsblocks.draggable, blocks.drag.grid, blocks.drag.bounds
    selectable, clipToScrollParentsinteraction.selectable, interaction.clipToScrollParents
    style.curvature, curveMinReach, curveMaxReach, curveAngleBlend, curveAngleMaxOffsetstyle.bezier.curvature, minReach, maxReach, angleBlend, angleMaxOffset
    style.cornerRadius, style.maxTrunkReachstyle.smoothstep.cornerRadius, style.smoothstep.maxTrunkReach
    style.avoidObstaclesstyle.routing.avoidObstacles
    style.startMarker, style.endMarkerstyle.markers.start, style.markers.end
    style.hoverStyle, style.selectedStylestyle.hover, style.selected
    hoverStyle.markerSize, selectedStyle.markerSizesize in the marker's own hover and selected
    VisualLinkerOptionsVisualLinkerConfig
  • Breaking (Vue): the options prop of <VisualLinker> is now config, and the UseVisualLinkerOptions of useVisualLinker() no longer extends the engine's options: it has config, blocks and connections. config is reactive, so changing it redraws the diagram. See VisualLinker Component.

  • Breaking (Vue): the shared configuration moves from a global object to Vue's provide/inject. setVisualLinkerDefaults(), resetVisualLinkerDefaults(), visualLinkerDefaults and the VisualLinkerDefaults type are removed. Pass the configuration to app.use(VisualLinkerPlugin, { config }), and change it later through useVisualLinkerConfig(). See Shared Configuration.

  • Breaking (Nuxt): the module options are the engine's configuration itself — the same theme, lines, markers, ports, labels, blocks and interaction groups — instead of a separate flat list (defaultCurve, portRadius, curvature, …). They must be JSON-serializable. The four settings the old list could not reach (defaultCornerRadius, defaultMaxTrunkReach, draggable, dragBounds) are now ordinary fields. The client-only plugin is gone; one universal plugin registers the directives and installs the configuration. See Nuxt Module.

  • Breaking (core): a marker configured in markers.start or markers.end replaces the built-in port dot at that end of every connection, as a marker set on a single connection always did. Marker colors now follow the theme's line colors too.

  • New (core): visual states for every visual entity. Lines, markers, ports and labels take highlight, hover, selected and focus buckets with the fields of the entity itself, stacked in that order over the base. A marker can change its shape, size, colors, outline, arrow or whole svg in a state; a port can grow, a label can change its fill. Markers, ports and labels follow the state of their connection. See Visual States.

  • New (core): the highlight state. A hovered block now puts its connections into highlight, apart from hover, the pointer over the line itself. Until a highlight bucket is set it looks the same as hover, so existing configurations look as before.

  • New (core): opacity for lines, markers, ports and labels, also per state. A marker without its own opacity fades with its line, and an animated line multiplies it with its dimming.

  • New (core): themes. A theme is a set of color tokens — line, lineHover, lineSelected, selectedHalo, focusRing, portFill, portStroke, labelBackground, labelBorder, labelText — written to CSS variables. lightTheme, darkTheme and defineTheme(overrides, base) are exported. See Themes.

  • New (core): labels group — background, border, color, fontSize, paddingX, paddingY and opacity of library-drawn labels, with states — and ports.side and ports.offset as the defaults for ports that set none of their own.

  • New (core): the configuration can be changed while the engine runs. setConfig(patch) deep-merges (a key set to undefined is removed), replaceConfig(next) replaces, getConfig() returns a copy. Dragging and selection are attached or detached to match, and everything is redrawn. Also exported: mergeConfig, patchConfig and mergeMarkerInputs.

  • New (Vue): the shared configuration. VisualLinkerPlugin takes { config }; useVisualLinkerConfig() returns the reactive object; provideVisualLinkerConfig(initial?) scopes one to a subtree; installVisualLinkerConfig, createSharedConfig and VISUAL_LINKER_CONFIG_KEY serve integrations. Every diagram merges it under its own config, and a change to it redraws all of them. Nothing is global, so several apps on a page do not interfere.

  • Changed (core): the block:mouseenter event puts the block's connections into highlight rather than hover, and the line under the pointer is the only one in hover.