Skip to content

quantumwake/kgraph

Repository files navigation

@quantumwake/kgraph

A lightweight, zero-dependency React graph canvas. Build node-based editors, pipelines, and diagrams with a familiar API — no Zustand, no d3, no CSS imports required.

If you've used ReactFlow, you'll feel right at home. If you haven't, you'll be up and running in 5 minutes.

kgraph example

Why KGraph?

ReactFlow KGraph
Runtime deps Zustand + d3-selection + d3-zoom + d3-drag None
CSS import Required Not needed
Bundle size ~150KB+ ~42KB
Source 100+ files, monorepo 12 files, ~2K LOC
Mental model Zustand store + d3 transforms React context + useState
API surface 19 hooks, 60+ types 2 hooks, 15 types

Install

npm install @quantumwake/kgraph
# or
yarn add @quantumwake/kgraph
# or
pnpm add @quantumwake/kgraph

Requires React 17+. That's it — no CSS files to import, no provider wrappers to add.

Quick Start

import { useState } from 'react';
import {
  KGraphCanvas,
  applyNodeChanges,
  applyEdgeChanges,
} from '@quantumwake/kgraph';
import type { KGraphNode, KGraphEdge, KGraphConnection } from '@quantumwake/kgraph';

function MyGraph() {
  const [nodes, setNodes] = useState<KGraphNode[]>([
    { id: '1', type: 'default', position: { x: 0, y: 0 }, data: { label: 'Hello' } },
    { id: '2', type: 'default', position: { x: 200, y: 120 }, data: { label: 'World' } },
  ]);
  const [edges, setEdges] = useState<KGraphEdge[]>([
    { id: 'e1', source: '1', target: '2' },
  ]);

  return (
    <div style={{ width: '100%', height: 600 }}>
      <KGraphCanvas
        nodes={nodes}
        edges={edges}
        onNodesChange={c => setNodes(applyNodeChanges(c, nodes))}
        onEdgesChange={c => setEdges(applyEdgeChanges(c, edges))}
        onConnect={(conn: KGraphConnection) =>
          setEdges(prev => [...prev, { id: `e-${Date.now()}`, ...conn }])
        }
        fitView
      />
    </div>
  );
}

That gives you pan, zoom, drag, snap-to-grid, selection, keyboard delete, a minimap, directed arrows, and a dot grid background — all out of the box.

Features

  • Zero dependencies — peer dep on React, nothing else
  • ReactFlow-compatible APIapplyNodeChanges, applyEdgeChanges, getBezierPath
  • Custom nodes & edges — bring your own React components
  • Connection drawing — drag from source handle to target handle
  • Interactive handles — visible dots with hover effects, crosshair cursor on sources
  • Directed arrows — SVG markers on all edges by default
  • MiniMap — click-to-navigate overview
  • Dot grid background — configurable gap
  • Edge labels — zoom-invariant HTML overlays
  • Viewport controlsuseKGraph() hook for fitView, zoomIn, zoomOut, zoomTo
  • Drag & droponDrop callback with canvas-space coordinates
  • Multi-select — Shift/Cmd+click
  • Keyboard shortcuts — Delete/Backspace to remove selected elements
  • Snap-to-grid — configurable grid size
  • Fully typed — TypeScript declarations included

Custom Nodes

import { Handle } from '@quantumwake/kgraph';
import type { NodeComponentProps } from '@quantumwake/kgraph';

const MyNode: React.FC<NodeComponentProps> = ({ data, selected }) => (
  <div style={{
    padding: 16, borderRadius: 8,
    border: `2px solid ${selected ? '#60a5fa' : '#333'}`,
    background: '#1a1a2e', color: '#fff',
  }}>
    <Handle id="target-1" type="target" position="top" />
    <h3>{data.title}</h3>
    <p>{data.description}</p>
    <Handle id="source-4" type="source" position="bottom" />
  </div>
);

// Register it:
<KGraphCanvas nodeTypes={{ myNode: MyNode }} ... />

Handle IDs map to positions: *-1 = top, *-2 = left, *-3 = right, *-4 = bottom.

Handles are visible by default (purple dots that grow on hover). Pass style={{ background: '#22c55e', borderColor: '#4ade80' }} to customize colors.

Custom Edges

import { getBezierPath } from '@quantumwake/kgraph';
import type { EdgeComponentProps } from '@quantumwake/kgraph';

const DashedEdge: React.FC<EdgeComponentProps> = (props) => {
  const [path] = getBezierPath(props);
  return (
    <g>
      <path d={path} fill="none" stroke="transparent" strokeWidth={20} />
      <path d={path} fill="none" stroke="#7c3aed" strokeWidth={2}
        strokeDasharray="8 4"
        markerEnd="url(#kgraph-arrow)" />
    </g>
  );
};

<KGraphCanvas edgeTypes={{ dashed: DashedEdge }} ... />

Arrow markers (#kgraph-arrow and #kgraph-arrow-selected) are defined automatically by KGraphCanvas.

Hooks

useKGraph()

Available inside any child of <KGraphCanvas>:

const {
  fitView,              // (options?) => void
  zoomIn,               // () => void
  zoomOut,              // () => void
  zoomTo,               // (level: number) => void
  getViewport,          // () => { x, y, zoom }
  setViewport,          // (viewport | updater) => void
  screenToCanvasPosition, // (clientX, clientY) => { x, y }
  getNodes,             // () => KGraphNode[]
  getEdges,             // () => KGraphEdge[]
} = useKGraph();

useKGraphContext()

Full internal context — containerRef, handle registration, canvasToScreenPosition, etc. Use this for advanced integrations.

Props Reference

Prop Type Default Description
nodes KGraphNode[] required Node array
edges KGraphEdge[] required Edge array
onNodesChange (changes) => void Node change callback
onEdgesChange (changes) => void Edge change callback
onConnect (connection) => void New connection callback
onNodeClick (event, node) => void Node click handler
onEdgeClick (event, edge) => void Edge click handler
onPaneClick (event) => void Background click handler
onDrop (event, position) => void Drop with canvas coordinates
nodeTypes Record<string, Component> {} Custom node components
edgeTypes Record<string, Component> {} Custom edge components
snapToGrid boolean true Snap node positions to grid
snapGrid [number, number] [16, 16] Grid cell size in px
panOnDrag boolean true Enable canvas panning
zoomOnScroll boolean true Enable scroll/pinch zoom
nodesDraggable boolean true Allow node dragging
nodesConnectable boolean true Allow connection drawing
elementsSelectable boolean true Allow click-to-select
fitView boolean false Auto-fit viewport on mount
showMiniMap boolean true Show minimap overlay
showBackground boolean true Show dot grid
backgroundGap number 32 Dot grid spacing
minZoom number 0.1 Minimum zoom level
maxZoom number 4 Maximum zoom level

Examples

9 interactive examples ship as a runnable Vite app:

cd examples && npm install && npm run dev

Open localhost:5173 — sidebar navigation across all demos:

Example What it shows
Basic Graph Simplest usage — 3 nodes, 2 edges
Custom Nodes Input/Processor/Output types with colored multi-handle
Custom Edges Labeled, animated, and success edge styles
Drag & Drop Palette panel, drag to create nodes
Viewport Controls Programmatic zoom/fit toolbar via useKGraph()
Interactive Callbacks Real-time event log for all interactions
Canvas Options Runtime toggle of every canvas prop
Large Graph 80-node grid for performance testing
MiniMap & Background Category-colored pipeline with minimap

All examples include drag & drop, right-click context menus, and connection drawing.

See EXAMPLES.md for detailed docs on each one.

Migrating from ReactFlow

KGraph's API is designed for easy migration:

  • <ReactFlow><KGraphCanvas>
  • <ReactFlowProvider> → not needed (provider is built in)
  • useReactFlow()useKGraph()
  • applyNodeChanges / applyEdgeChanges → same function names, same behavior
  • getBezierPath → same function name, same return signature
  • Node<T>KGraphNode, Edge<T>KGraphEdge
  • Remove your ReactFlow CSS import — KGraph uses inline styles

See COMPARISON.md for a full feature matrix against ReactFlow, React Diagrams, Reaflow, and X6.

Contributing

git clone https://github.com/quantumwake/kgraph.git
cd kgraph
npm install
npm run build     # builds dist/
npm run dev       # watch mode
npm run lint      # type-check

License

MIT

About

A workflow visualization react component

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors