The Qwik binding combines a flow component with sibling hooks, a generic diagram host, and a comment panel.
One headless model drives every framework binding; the Qwik components expose that model in Qwik's resumable app structure.
Prerequisites
Use Qwik 1.x; @grafloria/qwik 0.10.6 also declares @grafloria/element ^0.4.3 as a peer. For the shared engine and renderer peer ranges, see Vue quick start.
Install the binding and its peer packages:
bashnpm install @grafloria/qwik @grafloria/engine @grafloria/renderer @builder.io/qwik @grafloria/element
1. Render a flow
For what the flow, node and edge specs, and default-data props do, see React quick start. Here, GrafloriaFlow uses fitView to frame the mounted flow.
2. Connect a sibling toolbar
Wrap the flow and its toolbar in GrafloriaProvider. The sibling calls useGrafloria for the live instance, and useSelection and useViewport expose selection and camera state as reactive signals. Use useOnSelectionChange$ when a QRL handler needs each selection update; it receives a SelectionChange. The instance signal is undefined until the flow mounts.
This route combines the flow, sibling toolbar, comment panel, and generic spec host. The toolbar reads selection and viewport state; selecting a node also logs the selected node and edge counts. The comment panel waits for the flow's live instance, then receives its non-serializable comment store.
tsximport {
$,
component$,
noSerialize,
useSignal,
useVisibleTask$,
type NoSerialize,
} from '@builder.io/qwik';
import type { CommentStore } from '@grafloria/engine';
import {
GrafloriaCommentPanel,
GrafloriaDiagram,
GrafloriaFlow,
GrafloriaProvider,
useGrafloria,
useOnSelectionChange$,
useSelection,
useViewport,
type EdgeSpec,
type NodeSpec,
type SelectionChange,
} from '@grafloria/qwik';
const nodes: NodeSpec[] = [
{ id: 'plan', position: { x: 60, y: 60 }, size: { width: 160, height: 64 }, label: 'Plan' },
{ id: 'build', position: { x: 300, y: 60 }, size: { width: 160, height: 64 }, label: 'Build' },
{ id: 'test', position: { x: 540, y: 60 }, size: { width: 160, height: 64 }, label: 'Test' },
];
const edges: EdgeSpec[] = [
{ id: 'e1', source: 'plan', target: 'build', sourceHandle: 'right', targetHandle: 'left' },
{ id: 'e2', source: 'build', target: 'test', sourceHandle: 'right', targetHandle: 'left' },
];
const spec = { nodes, edges };
const Toolbar = component$(() => {
const instance = useGrafloria();
const selection = useSelection();
const viewport = useViewport();
useOnSelectionChange$($((change: SelectionChange) => {
console.info('Selection changed', change.nodes.length, change.edges.length);
}));
return (
<aside style={{ gridColumn: '1 / -1' }}>
<span>Flow {instance.value ? 'ready' : 'waiting'}</span>
<span>Zoom {viewport.value.zoom.toFixed(2)}</span>
<span>
Selected {selection.value.nodes.length} node(s), {selection.value.edges.length} edge(s)
</span>
</aside>
);
});
const CommentPanelHost = component$(() => {
const instance = useGrafloria();
const store = useSignal<NoSerialize<CommentStore>>();
useVisibleTask$(({ track }) => {
const diagram = track(() => instance.value);
if (!diagram) return;
const comments = diagram.getCommentStore();
if (!comments) return;
comments.createThread({ kind: 'node', id: 'plan' }, 'Confirm the handoff criteria.');
store.value = noSerialize(comments);
});
return store.value ? <GrafloriaCommentPanel store={store.value} /> : null;
});
export default component$(() => (
<GrafloriaProvider>
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 2fr) minmax(260px, 1fr)', gridTemplateRows: 'auto 400px' }}>
<Toolbar />
<GrafloriaFlow
defaultNodes={nodes}
defaultEdges={edges}
comments
fitView
style={{ height: '400px' }}
/>
<CommentPanelHost />
</div>
<GrafloriaDiagram spec={spec} style={{ height: '400px' }} />
</GrafloriaProvider>
));
3. Add an anchored comment panel
For the comment-store setup, see React quick start. In Qwik, GrafloriaCommentPanel appears after useVisibleTask$ reads the live instance and keeps its store in a signal wrapped with noSerialize().
4. Mount a spec with the generic diagram component
Use GrafloriaDiagram when your input is a diagram spec rather than the flow component's node and edge props. It accepts an object spec.
The object spec renders as a diagram in the component's container. A changed spec or options value replaces the mounted diagram and calls onReady$ again; an equal spec value does not trigger a replacement.
Where to go next
See the live Qwik demos to run the binding's examples, including the provider-and-hooks and generic spec examples. Continue with How Grafloria works for the shared model and instance concepts, or Build runnable workflows to make diagrams interactive for end users.
Was this page helpful?