# Qwik quick start

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](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/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](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/vue-quick-start).

Install the binding and its peer packages:

```bash
npm 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](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/react-quick-start). Here, [`GrafloriaFlow`](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/grafloria-qwik#grafloriaflow) uses `fitView` to frame the mounted flow.

## 2. Connect a sibling toolbar

Wrap the flow and its toolbar in [`GrafloriaProvider`](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/grafloria-qwik#grafloriaprovider). The sibling calls [`useGrafloria`](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/grafloria-qwik#usegrafloria) for the live instance, and [`useSelection`](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/grafloria-qwik#useselection) and [`useViewport`](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/grafloria-qwik#useviewport) expose selection and camera state as reactive signals. Use [`useOnSelectionChange$`](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/grafloria-qwik#useonselectionchange) when a QRL handler needs each selection update; it receives a [`SelectionChange`](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/grafloria-qwik#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.

```tsx
import {
  $,
  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](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/react-quick-start). In Qwik, [`GrafloriaCommentPanel`](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/grafloria-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`](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/grafloria-qwik#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](https://grafloria.com/demos-qwik/) to run the binding's examples, including the provider-and-hooks and generic spec examples. Continue with [How Grafloria works](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/how-grafloria-works) for the shared model and instance concepts, or [Build runnable workflows](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/build-runnable-workflows) to make diagrams interactive for end users.
