Get Started
Introduction
Components
Accordion
Badge
Button
Card
Checkbox
Command
Dialog
Dropdown Menu
Input
Select
Switch
Table
Tabs
Toast
Tooltip
Forms
Introduction
Validation
Field Arrays

Graph / DAG Editor

SVG-based node graph with reactive cx/cy/d/viewBox bindings, drag-to-move, drag-to-connect, and auto-layout toggle. Exercises the compiler's SVG namespace path that other blocks don't touch.

#Preview

100%
5 nodes5 edges
SourceFilterMapReduceSink
1"use client"23import { createSignal, createMemo } from '@barefootjs/client'45// Nodes and edges live in plain signals. The SVG view mirrors them6// directly: <circle cx={n.x}/> binds to a node's position, <path d=7// {edgePath(e)}/> rebuilds whenever any node moves, and the root8// <svg viewBox={viewBox()}/> reacts to zoom changes. Every other9// block uses HTML elements only — this is the first block to drive10// the compiler's SVG namespace path with reactive updates.1112function GraphEditor() {13  const [nodes, setNodes] = createSignal<GraphNode[]>(INITIAL_NODES)14  const [edges, setEdges] = createSignal<GraphEdge[]>(INITIAL_EDGES)15  const [zoom, setZoom] = createSignal(1)1617  const viewBox = createMemo(() => {18    const w = 720 / zoom(), h = 400 / zoom()19    return `${360 - w / 2} ${200 - h / 2} ${w} ${h}`20  })2122  function edgePath(e: GraphEdge): string {23    const map = nodeIndex()24    const s = map[e.source], t = map[e.target]25    return bezierPath(s.x, s.y, t.x, t.y)26  }2728  return (29    <svg viewBox={viewBox()} onPointerMove={onMove} onPointerUp={onUp}>30      {/* Edges: d rebuilds on any node move — mapArray over signal-derived list. */}31      <g>32        {edges().map(e => (33          <path key={e.id} d={edgePath(e)} stroke="#94a3b8" fill="none"/>34        ))}35      </g>3637      {/* Nodes: cx/cy on <circle>, x/y on <text>, plus a connect handle.38          Nested SVG children inside a single .map() body. */}39      <g>40        {nodes().map(n => (41          <g key={n.id} data-node-id={n.id} onPointerDown={onNodeDown}>42            <circle cx={n.x} cy={n.y} r={28} fill={KIND_FILL[n.kind]}/>43            <text x={n.x} y={n.y}>{n.label}</text>44            <circle cx={n.x + 28} cy={n.y} r={5} onPointerDown={onHandleDown}/>45          </g>46        ))}47      </g>48    </svg>49  )50}

#Features

SVG Namespace Attribute Bindings

Every other block in the gallery uses HTML elements only. This block is the first to bind signals to SVG attributes:cx andcy on<circle>,d on<path>,x /y on<text>, andviewBox on the root<svg>. The compiler must wire reactive bindings using the SVG namespace path so attributes update on the correct element.

Reactive `d` Path Rebuild

Each edge'sd attribute is recomputed from both endpoints' currentx /y. Dragging a node triggers d rebuilds for every edge connected to it, exercising path-string reactivity inside a mapArrayloop body.

Reactive viewBox

Zoom buttons rewrite the SVG viewBoxstring on every change, exercising attribute updates on the root SVG element.

Nested SVG Loops

The nodes loop renders a <g>wrapper containing a body<circle>, a<text> label, and a connect <circle>handle — three SVG children sharing the same loop scope. Each one carries reactive attribute bindings.

Drag-to-Connect with Preview Path

Pulling from a node's handle creates a temporary preview <path>tracking the cursor. The preview lives in a conditional branch (rendered only while dragging), exercising conditional SVG mounts. Releasing on another node creates a real edge.

Auto-Layout Swap

Toggling auto-layout replaces every node'sx /y simultaneously via topological column placement. Every reactivecx /cy /d binding must update on the same microtask without stale frames.