# JavaScript quick start

Mount an editable diagram in plain JavaScript, give its host and nodes a size, and keep the live instance for later updates.

Grafloria uses one headless engine beneath its framework bindings. In JavaScript, [`render`](https://atloria.dev/p/grafloria-h7YM7amryF/developer/grafloria-element-core) mounts data into an element and returns a [`DiagramInstance`](https://atloria.dev/p/grafloria-h7YM7amryF/developer/grafloria-renderer-instance-diagraminstance) that you use for updates, events, and camera operations.

## Prerequisites

Use a browser-based JavaScript project with Node.js and npm. Install the published packages:

```bash
npm install @grafloria/element @grafloria/renderer @grafloria/engine
```

## 1. Create a sized host

Give the host a resolved height. Give each node a `size` with its width and height; `position` places it in the diagram.

```html
<div id="canvas" style="height: 480px; width: 100%;"></div>
<script type="module" src="./main.js"></script>
```

The host is now large enough for the renderer to paint; the JavaScript sample gives each box explicit dimensions.

## 2. Render real data

Put nodes and edges in the render specification. The specification is data, not a Mermaid-style text string. Each edge refers to its source and target node by ID.

```js title="main.js"
import { render } from '@grafloria/element';

const canvas = document.getElementById('canvas');
if (!(canvas instanceof HTMLElement)) {
  throw new Error('The #canvas host is missing');
}
canvas.style.height = '480px';

const nodes = [
  {
    id: 'ingest',
    position: { x: 60, y: 80 },
    size: { width: 180, height: 80 },
    data: { label: 'Ingest' },
  },
  {
    id: 'publish',
    position: { x: 380, y: 80 },
    size: { width: 180, height: 80 },
    data: { label: 'Publish' },
  },
];

const edges = [
  { id: 'ingest-to-publish', source: 'ingest', target: 'publish' },
];

const api = render(
  { nodes, edges },
  canvas,
);

api.fitView(40);
window.addEventListener('pagehide', () => api.dispose(), { once: true });
```

The mounted canvas shows two editable boxes, `Ingest` and `Publish`, joined by an edge. You can drag nodes, draw connections, pan, zoom, and use Cmd/Ctrl+Z to undo. `fitView(40)` frames the content with 40 pixels of padding.

![The canvas shows the Ingest and Publish boxes connected by one edge.](https://atloriaassets.blob.core.windows.net/assets/a438221c-c1af-407c-b9e6-a56c986db846/d91de328beb165a2057c016d2af6de7d.png)

The `api` variable is the live [`DiagramInstance`](https://atloria.dev/p/grafloria-h7YM7amryF/developer/grafloria-renderer-instance-diagraminstance), not a copy of the input data. Subscribe to an instance event and update the mounted data through the instance methods:

```js title="main.js"
import { render } from '@grafloria/element';

const nodes = [
  { id: 'ingest', position: { x: 60, y: 80 }, size: { width: 180, height: 80 }, data: { label: 'Ingest' } },
  { id: 'publish', position: { x: 380, y: 80 }, size: { width: 180, height: 80 }, data: { label: 'Publish' } },
];
const edges = [{ id: 'ingest-to-publish', source: 'ingest', target: 'publish' }];
const canvas = document.getElementById('canvas');
if (!(canvas instanceof HTMLElement)) {
  throw new Error('The #canvas host is missing');
}
canvas.style.height = '480px';

const api = render({ nodes, edges }, canvas);
const unsubscribe = api.on('nodes:change', ({ nodes: changedNodes }) => {
  console.log('nodes in the live model:', changedNodes.length);
});

const nextNodes = [
  ...nodes,
  { id: 'archive', position: { x: 700, y: 80 }, size: { width: 180, height: 80 }, data: { label: 'Archive' } },
];
const nextEdges = [
  ...edges,
  { id: 'publish-to-archive', source: 'publish', target: 'archive' },
];

api.setEdges([]);
api.setNodes([]);
api.setNodes(nextNodes);
api.setEdges(nextEdges);

api.fitView(40);
window.addEventListener('pagehide', () => {
  unsubscribe();
  api.dispose();
}, { once: true });
```

The canvas now contains a third box and a second edge. The listener receives the live node-change payload; calling the returned function removes that listener.

![The canvas shows Archive added to the right of Publish with a second edge.](https://atloriaassets.blob.core.windows.net/assets/a438221c-c1af-407c-b9e6-a56c986db846/65677bd94ceb34e23b57de8248eb1355.png)

When replacing edited data that reuses persistent IDs, clear the existing edges and nodes before applying the replacement. Reconciliation preserves existing live models, so applying replacement arrays alone can retain stale models.

## 3. Clean up with the page lifecycle

Dispose the instance when the host leaves the page. Do not dispose it immediately after mounting: disposal removes the live diagram. The first sample registers this cleanup with `pagehide`.

## Use the custom element instead

[`GrafloriaFlowElement`](https://atloria.dev/p/grafloria-h7YM7amryF/developer/grafloria-element-core) is the web-component form of the same editor. Import the package once, put JSON data in its `nodes` and `edges` attributes, and give the element a height.

```html title="index.html"
<style>
  grafloria-flow { display: block; height: 480px; width: 100%; }
</style>
<grafloria-flow
  fit-view
  nodes='[{"id":"extract","position":{"x":60,"y":80},"size":{"width":180,"height":80},"label":"Extract"},{"id":"load","position":{"x":380,"y":80},"size":{"width":180,"height":80},"label":"Load"}]'
  edges='[{"id":"extract-to-load","source":"extract","target":"load"}]'>
</grafloria-flow>

<script type="module">
  import { GrafloriaFlowElement } from '@grafloria/element';
  import '@grafloria/element';

  const element = document.querySelector('grafloria-flow');
  if (!(element instanceof GrafloriaFlowElement)) {
    throw new Error('The grafloria-flow element is missing');
  }
  element.addEventListener('grafloria-connect', (event) => {
    console.log('connected:', event.detail.link);
  });
</script>
```

This version shows the same editable two-node diagram without a framework component. Its `grafloria-connect` listener receives the connected link.

![The custom-element canvas shows Extract and Load as connected boxes.](https://atloriaassets.blob.core.windows.net/assets/a438221c-c1af-407c-b9e6-a56c986db846/f38a972307e28cb462728d84295efeec.png)

## What you have at the end

You have an editable, sized diagram backed by plain node and edge data, plus a live instance for fitting the view, listening for changes, replacing data, and disposing the renderer. The repository's [JavaScript starter](https://github.com/grafloria/grafloria/blob/ef2bcc55237d4d1f1643b6fea68bd996aa37a9e9/starters/javascript) uses the same mounting shape. Try it at the [JavaScript live demo](https://grafloria.com/javascript/).

For layout, themes, and other engine behavior, continue to [How Grafloria works](https://atloria.dev/p/grafloria-h7YM7amryF/developer/how-grafloria-works).
