# Apply auto-layout

Use a mounted graph's layout registry to arrange its nodes, then fit the resulting diagram into the canvas. The same graph model drives the JavaScript, Angular, React, and Vue bindings.

## Choose a layout

Use the mounted [`DiagramInstance`](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/grafloria-renderer-instance-diagraminstance#diagraminstance) as the facade for the live diagram. In JavaScript, call `getEngine()` and await the engine's layout operation. The call changes the live model and returns a layout result; call `renderNow()` before fitting when you need the repaint immediately.

Registered names include `auto`, `elk`, `dagre`, `layered`, `tree`, `grid`, `circular`, `radial`, `force`, `spectral`, and `community`. Use `auto` when you want the engine to choose from the graph's shape. Use `dagre`, `layered`, or `elk` for pipelines and DAGs; use `tree` for hierarchies; use `grid`, `circular`, or `radial` for uniform collections; and use `force`, `community`, or `spectral` for networks. An unknown name throws instead of silently leaving the graph unchanged.

The object form supplies layout options. `nodeSpacing` and `rankSpacing` control the gaps used by the shipped layered layouts.

## JavaScript

Mount real data with [`render`](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/grafloria-element-core#render), run the chosen layout, repaint, and frame all content. The host has an explicit height so the fitted diagram has a visible canvas.

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

const host = document.querySelector('#diagram');
if (!(host instanceof HTMLElement)) throw new Error('The #diagram element is required');

const spec = {
  nodes: [
    { id: 'root', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Root' },
    { id: 'left', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Left' },
    { id: 'right', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Right' },
  ],
  edges: [
    { id: 'root-left', source: 'root', target: 'left' },
    { id: 'root-right', source: 'root', target: 'right' },
  ],
};

host.style.height = '400px';

const instance = render(spec, host);

async function arrange() {
  const result = await instance.getEngine().layout('dagre', {
    nodeSpacing: 40, rankSpacing: 80,
  });
  instance.renderNow();
  instance.fitView(40);
  console.log(result.bounds);
}

void arrange();
```

The three nodes start at the same position, then appear as a left-to-right tree. `result.bounds` is the bounding box of the laid-out graph, while `fitView(40)` frames all content with 40 world units of padding.

## Framework bindings

The declarative `layout` prop runs the layout when its value changes. It does not re-run when node data changes, so it does not fight a user's drag. Set `fitView` on the flow to fit the rendered graph.

:::code-group
```ts title="Angular"
import { Component } from '@angular/core';
import { DiagramCanvasComponent } from '@grafloria/angular';
import type { EdgeSpec, NodeSpec } from '@grafloria/renderer';

@Component({
  standalone: true,
  imports: [DiagramCanvasComponent],
  template: `
    <grafloria-diagram-canvas [(nodes)]="nodes" [(edges)]="edges"
      [layout]="layout" [plugins]="true" style="display:block;height:100vh" />
  `,
})
export class LayoutDemo {
  layout = { name: 'dagre', options: { nodeSpacing: 40, rankSpacing: 80 } };
  nodes: NodeSpec[] = [
      { id: 'root', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Root' },
    { id: 'left', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Left' },
    { id: 'right', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Right' },
  ];
  edges: EdgeSpec[] = [
    { id: 'root-left', source: 'root', target: 'left' },
    { id: 'root-right', source: 'root', target: 'right' },
  ];
}
```
```text title="Qwik"
import { component$ } from '@builder.io/qwik';
import { GrafloriaFlow, type EdgeSpec, type NodeSpec } from '@grafloria/qwik';

const layout = { name: 'dagre', options: { nodeSpacing: 40, rankSpacing: 80 } };
const nodes: NodeSpec[] = [
  { id: 'root', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Root' },
  { id: 'left', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Left' },
  { id: 'right', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Right' },
];
const edges: EdgeSpec[] = [
  { id: 'root-left', source: 'root', target: 'left' },
  { id: 'root-right', source: 'root', target: 'right' },
];

export default component$(() => (
  <div style={{ height: '100vh' }}>
    <GrafloriaFlow defaultNodes={nodes} defaultEdges={edges} layout={layout} />
  </div>
));
```
```tsx title="React"
import { GrafloriaFlow } from '@grafloria/react';
import type { EdgeSpec, NodeSpec } from '@grafloria/react';

const layout = { name: 'dagre', options: { nodeSpacing: 40, rankSpacing: 80 } };
const nodes: NodeSpec[] = [
  { id: 'root', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Root' },
  { id: 'left', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Left' },
  { id: 'right', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Right' },
];
const edges: EdgeSpec[] = [
  { id: 'root-left', source: 'root', target: 'left' },
  { id: 'root-right', source: 'root', target: 'right' },
];

export default function LayoutDemo() {
  return <div style={{ height: '100vh' }}><GrafloriaFlow defaultNodes={nodes} defaultEdges={edges} layout={layout} fitView /></div>;
}
```
```vue title="Vue"
<script setup lang="ts">
import { GrafloriaFlow } from '@grafloria/vue';
import type { EdgeSpec, NodeSpec } from '@grafloria/vue';

const layout = { name: 'dagre', options: { nodeSpacing: 40, rankSpacing: 80 } };
const nodes: NodeSpec[] = [
  { id: 'root', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Root' },
  { id: 'left', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Left' },
  { id: 'right', position: { x: 0, y: 0 }, size: { width: 130, height: 52 }, label: 'Right' },
];
const edges: EdgeSpec[] = [
  { id: 'root-left', source: 'root', target: 'left' },
  { id: 'root-right', source: 'root', target: 'right' },
];
</script>
<template>
  <div style="height:100vh"><GrafloriaFlow :default-nodes="nodes" :default-edges="edges" :layout="layout" fit-view /></div>
</template>
```
:::

Angular's `[plugins]="true"` adds canvas controls, including Fit. After the layout completes, use that control to frame the tree. In the other bindings, `fitView` performs the same framing as part of the mounted flow.

For an imperative rerun, capture the instance through the binding's initialization callback and call `instance.getEngine().layout(...)`, followed by `instance.fitView(40)`. Angular exposes the same operation as `applyLayout()` on its canvas component; its `layoutDone` output fires after the operation completes.

## Options that matter

| Option | Type | Default | What it does |
|---|---|---|---|
| `layout` | `string \| { name: string; options?: Record<string, unknown> }` | — | Selects a registered algorithm and optional settings. |
| `direction` | layout option | — | Sets the flow direction for supported layouts. |
| `nodeSpacing` | layout option | — | Sets spacing between nodes where supported. |
| `rankSpacing` | layout option | — | Sets spacing between ranks where supported. |
| `fitView` | `boolean` | — | Fits the mounted flow's content into its view. |

## Pitfalls

- Give the canvas host a real height. A percentage height resolves to zero when its ancestors have no height, leaving nothing to fit.
- A declarative layout reacts to changes in the layout value, not to node changes. Call the instance's engine for an explicit rerun after editing the graph.
- `elk` loads its heavier implementation on first use. Choose it when its layered and port-aware behavior matters; use a smaller shipped layout for a lightweight arrangement.
- Layout changes node positions and invalidates stale edge routes. Repaint the instance before measuring or exporting the result.

## See it running

Open the [auto-layout demo](https://grafloria.com/demos/layout/auto-layout.html) to switch between algorithms on a graph whose nine nodes begin stacked at the origin. The demo runs a layout, repaints, and fits the view after each switch.

For a fixed top-down hierarchy, see the [Dagre tree demo](https://grafloria.com/demos/layout/dagre-tree.html). For incremental placement that preserves the existing mental map, see [dynamic layouting](https://grafloria.com/demos/layout/dynamic-layouting.html).

## Related

- [How Grafloria works](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/how-grafloria-works)
- [Layout and routing](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/layout-and-routing)
- [Instance and lifecycle](https://bench-grafloria-56.atloria.app/p/bench-grafloria-56-62cg8vR5rF/developer/instance-and-lifecycle)
