How to Add Interactive Links and Highlights to SVG Diagrams Using YAML Metadata Files in Astro-Big-Doc

Astro-Big-Doc automatically transforms static SVG diagrams into interactive visualizations by pairing them with YAML metadata files that define clickable links and hover highlights, requiring no code changes to the SVG itself.

The astro-big-doc repository provides a built-in mechanism for enhancing SVG diagrams with interactivity through external metadata. By placing a YAML file alongside your SVG asset, you can define clickable regions and hover-triggered highlights without modifying the original vector graphic. This approach keeps content separate from presentation while delivering rich, interactive documentation experiences.

How the YAML-to-SVG Pipeline Works

Astro-Big-Doc processes SVG interactivity through a five-stage pipeline that bridges server-side asset resolution with client-side DOM manipulation:

  1. Asset Resolution – When an SVG is referenced in Markdown, the MarkdownImage.astro component invokes getMetaData() from src/libs/assets.js (lines 184-198). This function constructs a parallel file path by replacing the .svg extension with .yaml and checks for existence using exists().

  2. Metadata Injection – The parsed YAML object is passed as the meta prop to the Panzoom component (src/components/panzoom/panzoom.astro, lines 13-36). The component serializes the metadata into a data-meta attribute on the container element using JSON.stringify(meta) (line 35).

  3. Client-Side Processing – On page load, panzoom_common.js (lines 21-30) reads the data-meta attribute, parses the JSON, and conditionally invokes svg_add_links() and svg_highlight() from src/components/panzoom/lib_svg_utils.js (lines 29-146).

  4. Link Insertion – The svg_add_links() function (lines 30-55) traverses all <text> nodes in the SVG DOM, compares their textContent against the label fields in the metadata's links array, and wraps matches in SVG.js linkTo elements pointing to the specified URLs.

  5. Hover Highlights – The svg_highlight() function (lines 57-96) attaches mouseover and mouseout event listeners to trigger labels. When activated, it recolors (fill({color:'#292'})) and bolds every SVG text node whose content matches entries in the corresponding highlights array.

YAML Schema for SVG Interactivity

The metadata file uses a strict schema with two top-level arrays: links for clickable navigation and highlights for visual emphasis on hover.

The links array contains objects that map SVG text labels to URLs:

links:
  - label: "Home"
    link: "/"                     # Absolute URL opens in new tab

  - label: "API Reference"
    link: "/api/docs"             # Relative URL navigates in-page

  - label: "GitHub Repository"
    link: "https://github.com/microwebstacks/astro-big-doc"

Key constraints:

  • The label value must exactly match the text content of an SVG <text> node (case-sensitive)
  • Absolute URLs (starting with http or https) automatically open in new tabs
  • Relative URLs and anchors (#section) navigate within the current page context

Highlights Configuration

The highlights array defines hover-triggered visual connections between diagram elements:

highlights:
  - label: "Critical Path"
    highlights:
      - "Step 1"
      - "Step 3"
      - "Database"
  - label: "Optional Path"
    highlights:
      - "Step 2"
      - "Step 4"

Behavior details:

  • When the user hovers over the SVG text matching label, all nodes listed in the nested highlights array receive a green fill (#292) and bold font weight
  • Moving the mouse out restores the original styling
  • Multiple highlight groups can reference the same target nodes

Step-by-Step Implementation Guide

Follow these steps to add interactivity to any SVG diagram in your Astro-Big-Doc project:

  1. Prepare your assets

    • Export your diagram as diagram.svg and place it in your content directory (e.g., src/content/docs/architecture/)
  2. Create the metadata file

    • In the same directory, create diagram.yaml with your links and highlights configuration:
    links:
      - label: "Frontend"
        link: "/frontend-guide"
      - label: "Backend"
        link: "https://api.example.com"
    
    highlights:
      - label: "Frontend"
        highlights:
          - "React Component"
          - "CSS Module"
  3. Reference in Markdown

    • Use standard Markdown image syntax. The MarkdownImage.astro component (located at src/components/markdown/image/MarkdownImage.astro) automatically detects the companion YAML file:
    ![Architecture Diagram](diagram.svg)
  4. Verify the build

    • Run pnpm run dev and navigate to your page
    • Inspect the SVG container to confirm the data-meta attribute contains your YAML data
    • Test that clicking labeled elements navigates to the specified URLs
    • Hover over trigger labels to verify target nodes highlight in green

Technical Deep Dive: Source Code Architecture

Understanding the underlying implementation helps troubleshoot edge cases and extend functionality.

Asset Resolution Layer

The getMetaData() function in src/libs/assets.js (lines 184-198) handles the filesystem lookup:

// Simplified logic from src/libs/assets.js
export async function getMetaData(url, dirpath) {
  const basePath = resolvePath(url, dirpath);
  const yamlPath = basePath.replace(/\.[^/.]+$/, '.yaml');
  
  if (await exists(yamlPath)) {
    return await load_yaml_abs(yamlPath);
  }
  return null;
}

This convention-based approach means any asset type can potentially support metadata by following the {filename}.{ext} → {filename}.yaml pattern.

Component Integration

The Panzoom.astro component (src/components/panzoom/panzoom.astro, lines 13-36) serves as the bridge between server-side data and client-side execution:

---
// Props interface includes meta object
const { src, alt, meta } = Astro.props;
---

<div class="panzoom-container" data-meta={JSON.stringify(meta)}>
  <object data={src} type="image/svg+xml" aria-label={alt}></object>
</div>

The data-meta attribute stores the serialized YAML content, making it accessible to the client-side JavaScript without requiring additional fetch requests.

Client-Side Processing Engine

The panzoom_common.js file (src/components/panzoom/panzoom_common.js, lines 21-30) orchestrates the interactivity:

// Executed after DOMContentLoaded
const containers = document.querySelectorAll('.panzoom-container');
containers.forEach(container => {
  const metaAttr = container.getAttribute('data-meta');
  if (metaAttr) {
    const meta = JSON.parse(metaAttr);
    if (meta.links) svg_add_links(svgElement, meta.links);
    if (meta.highlights) svg_highlight(svgElement, meta.highlights);
  }
});

This initialization pattern ensures that SVG manipulation only occurs after the <object> element has fully loaded the SVG document.

SVG Manipulation Utilities

The lib_svg_utils.js file (src/components/panzoom/lib_svg_utils.js, lines 29-146) contains the core DOM manipulation logic using SVG.js:

Link Creation (lines 30-55):

export function svg_add_links(svgElement, links) {
  const texts = svgElement.querySelectorAll('text');
  texts.forEach(textNode => {
    const content = textNode.textContent.trim();
    const match = links.find(l => l.label === content);
    if (match) {
      // SVG.js wrapper for link creation
      const svgText = SVG(textNode);
      svgText.linkTo(match.link);
    }
  });
}

Highlight System (lines 57-96):

export function svg_highlight(svgElement, highlights) {
  highlights.forEach(entry => {
    const triggerNode = findTextNode(svgElement, entry.label);
    if (!triggerNode) return;
    
    triggerNode.addEventListener('mouseover', () => {
      entry.highlights.forEach(targetLabel => {
        const target = findTextNode(svgElement, targetLabel);
        if (target) {
          SVG(target).fill({ color: '#292' }).font({ weight: 'bold' });
        }
      });
    });
    
    triggerNode.addEventListener('mouseout', () => {
      // Reset logic omitted for brevity
    });
  });
}

Code Examples

Create network-diagram.yaml alongside your SVG:

links:
  - label: "Load Balancer"
    link: "/infrastructure/load-balancer"
  - label: "Database Cluster"
    link: "https://db.internal.company.com"

Configuration with Hover Highlights Only

Create workflow.yaml:

highlights:
  - label: "Initialization"
    highlights:
      - "Config Load"
      - "Cache Warmup"
  - label: "Processing"
    highlights:
      - "Worker Pool"
      - "Queue Manager"

Complete Markdown Integration

File: src/content/docs/architecture.md


# System Architecture

The following diagram illustrates component relationships. Hover over any service to see its dependencies, or click labels to navigate to detailed documentation.

![Architecture Overview](architecture.svg)

Required companion file: src/content/docs/architecture.yaml

links:
  - label: "API Gateway"
    link: "/api/gateway"
  - label: "Auth Service"
    link: "https://auth.example.com"

highlights:
  - label: "API Gateway"
    highlights:
      - "Rate Limiter"
      - "Router"
  - label: "Auth Service"
    highlights:
      - "JWT Validator"
      - "User Store"

Summary

  • Convention-based pairing: Astro-Big-Doc automatically associates diagram.svg with diagram.yaml when placed in the same directory, triggered by the getMetaData() function in src/libs/assets.js.
  • Zero-code configuration: The YAML schema supports two interaction modes—links for navigation and highlights for visual emphasis—without requiring modifications to the SVG source.
  • Client-side activation: The panzoom_common.js bootstrapper reads JSON-encoded metadata from the data-meta attribute (injected by Panzoom.astro) and delegates DOM manipulation to svg_add_links() and svg_highlight() in lib_svg_utils.js.
  • SVG.js integration: Link creation uses the linkTo() API, while highlights manipulate fill colors (#292) and font weights through SVG.js wrappers for robust cross-browser SVG manipulation.

Frequently Asked Questions

What happens if the YAML file is missing or malformed?

If diagram.yaml is absent, getMetaData() in src/libs/assets.js returns null, and the SVG renders as a static image without interactivity. If the YAML contains syntax errors, load_yaml_abs() will throw a parsing error during the build process, halting compilation until the file is fixed.

Can I use this feature with SVGs embedded directly in Markdown rather than referenced as files?

No. The current implementation in MarkdownImage.astro specifically processes external file references to enable the filesystem-based metadata lookup. Inline SVGs in Markdown bypass the asset resolution pipeline and will not trigger the getMetaData() call or the subsequent Panzoom wrapping.

The highlight color is hardcoded to #292 (green) in svg_highlight() within src/components/panzoom/lib_svg_utils.js (line 78). To customize colors, modify the fill({color:'#292'}) call or extend the YAML schema to accept a color property and update the utility function to read it. Link styling inherits from the SVG.js linkTo() implementation, which creates standard SVG <a> elements.

Does this work with server-side rendering (SSR) or only static builds?

The feature works in both modes. During SSR or static generation, the Panzoom.astro component embeds the metadata as a JSON string in the data-meta attribute. The interactivity is then hydrated client-side by panzoom_common.js, ensuring the SVG DOM is fully loaded before svg_add_links() and svg_highlight() execute, regardless of the build output mode.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →