The Qwik diagram library that renders on the server
Node editors and flow charts as Qwik components — QRL callbacks (onInit$, onNodesChange$), your own component$ as a custom node, hooks for selection and viewport. The server sends the finished diagram in the HTML, and the browser resumes it instead of redrawing it. Underneath: obstacle-avoiding routing, ELK auto-layout, undo/redo, CRDT collaboration and SVG/PNG/PDF export. MIT, no Pro tier.
import { component$, $ } from '@builder.io/qwik'; import { GrafloriaFlow, type NodeProps } from '@grafloria/qwik'; // Your own Qwik component draws the 'job' nodes. const Job = component$((p: NodeProps<{ title: string }>) => ( <div class="job-card">{p.data.title}</div> )); export const Flow = component$(() => ( <GrafloriaFlow nodes={[ { id: 'a', type: 'job', position: { x: 0, y: 0 }, data: { title: 'Extract' } }, { id: 'b', position: { x: 260, y: 0 }, label: 'Load' }, ]} edges={[{ source: 'a', target: 'b' }]} nodeTypes={{ job: Job }} layout="elk" onNodeClick$={$(({ node }) => console.log(node.id))} /> ));
Why teams pick it
Idiomatic Qwik
Every callback is a QRL, so it loads lazily. Custom nodes are plain component$s keyed by node type, and <GrafloriaProvider> with useGrafloria(), useSelection() and useViewport() lets a toolbar or inspector drive the canvas.
Server-rendered, then resumed
renderToStaticSVG() runs the real renderer in Node with no DOM. Pass the result as ssr: the page is correct before any script runs, and the browser adopts that markup with no hydration pass and no re-layout.
The hard parts are library code
Obstacle-avoiding orthogonal routing with jump-overs, ELK/dagre/force layout in a worker, one-gesture-one-undo command history, the drag-and-pack dashboard kit, UML/ER kits.
Server rendering in three lines
const ssr = renderToStaticSVG({ nodes, edges, width: 900, height: 420, fitView: true }); on the server, <GrafloriaFlow nodes={nodes} edges={edges} ssr={ssr} /> in the component, and ssr.css in the document head. The diagram’s script starts once the page is ready, so onInit$ fires and the hooks have the instance before anyone touches it. Custom nodes are framework components, so they mount in the browser, inside the layer the server already sent.
One engine, five surfaces
The identical JSON spec drives Qwik, React, Angular, Vue and the plain web component — and the same model exports to Mermaid text, SVG, PNG and true-vector PDF, in the browser or in Node. Move a diagram between apps without rewriting it.
Every demo, in your framework
The gallery is the documentation: every demo is a real, clickable page, and our CI
drives each one with real pointer events so the examples can't rot — and each one is available as a Qwik component, source shown.
Qwik demos — every gallery page as a real Qwik component →
Server rendering with resume has its own app: clone the repository and run
npx vite --config apps/demos-qwik/vite.config.ts --mode ssr.
Grafloria is MIT — every feature, no commercial tier. A custom node renders in its own Qwik
container, so it cannot read contexts from the surrounding app; feed it through node.data.
Qwik, React, Angular and Vue are trademarks of their respective owners; no affiliation implied.
Corrections welcome via GitHub issues.