# Style and label edges

Use edge specifications to choose a route, draw labels and arrowheads, and make crossing edges visibly hop. A mounted diagram renders each of these settings as part of its live graph.

This page focuses on the visual changes edge settings make in a mounted graph; for framework-specific setup and entry points, see [Build runnable workflows](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/build-runnable-workflows).

## Set route geometry and appearance

For the distinction among `type`, `router`, and `connector`, see [Diagram intent and rendering](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/diagram-intent-and-rendering); this mounted graph shows the visible differences: sharp versus rounded corners, distinct labels and markers, and hops at crossings.

The `style` field accepts a partial [`LinkStyle`](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/grafloria-engine-types-linkstyle#linkstyle); it carries stroke properties, arrowheads, and crossing configuration. In all the framework samples, the canvas has a fixed height so the rendered diagram has space to appear.

:::code-group
```js title="JavaScript"
import { render } from '@grafloria/element';
const target = document.getElementById('app');
if (!target) throw new Error('Missing #app');
target.style.height = '900px';

const nodes = [
  { id: 'a', position: { x: 80, y: 80 }, size: { width: 140, height: 56 }, label: 'Direct' },
  { id: 'b', position: { x: 570, y: 150 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'c', position: { x: 80, y: 230 }, size: { width: 140, height: 56 }, label: 'Sharp step' },
  { id: 'd', position: { x: 570, y: 300 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'e', position: { x: 80, y: 380 }, size: { width: 140, height: 56 }, label: 'Rounded step' },
  { id: 'f', position: { x: 570, y: 450 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'g', position: { x: 80, y: 530 }, size: { width: 140, height: 56 }, label: 'Bezier' },
  { id: 'h', position: { x: 570, y: 600 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'i', position: { x: 760, y: 680 }, size: { width: 120, height: 48 }, label: 'Cross A' },
  { id: 'j', position: { x: 1040, y: 680 }, size: { width: 120, height: 48 }, label: 'Cross D' },
  { id: 'k', position: { x: 760, y: 840 }, size: { width: 120, height: 48 }, label: 'Cross B' },
  { id: 'l', position: { x: 1040, y: 840 }, size: { width: 120, height: 48 }, label: 'Cross C' },
];

const edges = [
  { id: 'direct', source: 'a', target: 'b', type: 'direct', label: 'direct', labelPlacement: 'above', labelStyle: { color: '#1d4ed8', fontSize: 12 }, style: { stroke: '#2563eb', strokeWidth: 2, arrowHead: { type: 'arrow', size: 14, filled: true } } },
  { id: 'sharp', source: 'c', target: 'd', router: 'orthogonal', connector: 'straight', label: 'sharp corners', labelPlacement: 'above', style: { stroke: '#475569', strokeDasharray: '6 3', arrowHead: { type: 'diamond', size: 14, filled: false } } },
  { id: 'rounded', source: 'e', target: 'f', router: 'orthogonal', connector: 'rounded', label: 'rounded corners', labelPlacement: 'below', labelStyle: { background: '#eff6ff', padding: 4, borderRadius: 4 }, style: { stroke: '#059669', strokeWidth: 2, arrowHead: { type: 'crow-foot', size: 14, filled: false } } },
  { id: 'curve', source: 'g', target: 'h', type: 'bezier', label: 'no arrowhead', style: { stroke: '#9333ea', strokeWidth: 2, arrowHead: { type: 'none', size: 14, filled: false } } },
  { id: 'cross-ad', source: 'i', target: 'l', type: 'direct', style: { stroke: '#0f766e', jumpPoints: { enabled: true, size: 10, detectMode: 'all' } } },
  { id: 'cross-bc', source: 'k', target: 'j', type: 'direct', style: { stroke: '#b91c1c', jumpPoints: { enabled: true, size: 10, detectMode: 'all' } } },
];

render({ nodes, edges }, target);
```
```ts title="Angular"
import { Component } from '@angular/core';
import { DiagramCanvasComponent } from '@grafloria/angular';
import type { EdgeSpec } from '@grafloria/renderer';

@Component({
  standalone: true,
  imports: [DiagramCanvasComponent],
  template: `
    <grafloria-diagram-canvas [(nodes)]="nodes" [(edges)]="edges"
      style="display:block; height:900px" />
  `,
})
export class EdgeStylesComponent {
  nodes = [
    { id: 'a', position: { x: 80, y: 80 }, size: { width: 140, height: 56 }, label: 'Direct' },
    { id: 'b', position: { x: 570, y: 150 }, size: { width: 140, height: 56 }, label: 'Target' },
    { id: 'c', position: { x: 80, y: 230 }, size: { width: 140, height: 56 }, label: 'Sharp step' },
    { id: 'd', position: { x: 570, y: 300 }, size: { width: 140, height: 56 }, label: 'Target' },
    { id: 'e', position: { x: 80, y: 380 }, size: { width: 140, height: 56 }, label: 'Rounded step' },
    { id: 'f', position: { x: 570, y: 450 }, size: { width: 140, height: 56 }, label: 'Target' },
    { id: 'g', position: { x: 80, y: 530 }, size: { width: 140, height: 56 }, label: 'Bezier' },
    { id: 'h', position: { x: 570, y: 600 }, size: { width: 140, height: 56 }, label: 'Target' },
    { id: 'i', position: { x: 760, y: 680 }, size: { width: 120, height: 48 }, label: 'Cross A' },
    { id: 'j', position: { x: 1040, y: 680 }, size: { width: 120, height: 48 }, label: 'Cross D' },
    { id: 'k', position: { x: 760, y: 840 }, size: { width: 120, height: 48 }, label: 'Cross B' },
    { id: 'l', position: { x: 1040, y: 840 }, size: { width: 120, height: 48 }, label: 'Cross C' },
  ];
  edges: EdgeSpec[] = [
    { id: 'direct', source: 'a', target: 'b', type: 'direct', label: 'direct', labelPlacement: 'above', labelStyle: { color: '#1d4ed8', fontSize: 12 }, style: { stroke: '#2563eb', strokeWidth: 2, arrowHead: { type: 'arrow', size: 14, filled: true } } },
    { id: 'sharp', source: 'c', target: 'd', router: 'orthogonal', connector: 'straight', label: 'sharp corners', labelPlacement: 'above', style: { stroke: '#475569', strokeDasharray: '6 3', arrowHead: { type: 'diamond', size: 14, filled: false } } },
    { id: 'rounded', source: 'e', target: 'f', router: 'orthogonal', connector: 'rounded', label: 'rounded corners', labelPlacement: 'below', labelStyle: { background: '#eff6ff', padding: 4, borderRadius: 4 }, style: { stroke: '#059669', strokeWidth: 2, arrowHead: { type: 'crow-foot', size: 14, filled: false } } },
    { id: 'curve', source: 'g', target: 'h', type: 'bezier', label: 'no arrowhead', style: { stroke: '#9333ea', strokeWidth: 2, arrowHead: { type: 'none', size: 14, filled: false } } },
    { id: 'cross-ad', source: 'i', target: 'l', type: 'direct', style: { stroke: '#0f766e', jumpPoints: { enabled: true, size: 10, detectMode: 'all' } } },
    { id: 'cross-bc', source: 'k', target: 'j', type: 'direct', style: { stroke: '#b91c1c', jumpPoints: { enabled: true, size: 10, detectMode: 'all' } } },
  ];
}
```
```tsx title="Qwik"
import { render as renderQwik } from '@builder.io/qwik';
import { GrafloriaFlow, type EdgeSpec } from '@grafloria/qwik';

const nodes = [
  { id: 'a', position: { x: 80, y: 80 }, size: { width: 140, height: 56 }, label: 'Direct' },
  { id: 'b', position: { x: 570, y: 150 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'c', position: { x: 80, y: 230 }, size: { width: 140, height: 56 }, label: 'Sharp step' },
  { id: 'd', position: { x: 570, y: 300 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'e', position: { x: 80, y: 380 }, size: { width: 140, height: 56 }, label: 'Rounded step' },
  { id: 'f', position: { x: 570, y: 450 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'g', position: { x: 80, y: 530 }, size: { width: 140, height: 56 }, label: 'Bezier' },
  { id: 'h', position: { x: 570, y: 600 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'i', position: { x: 760, y: 680 }, size: { width: 120, height: 48 }, label: 'Cross A' },
  { id: 'j', position: { x: 1040, y: 680 }, size: { width: 120, height: 48 }, label: 'Cross D' },
  { id: 'k', position: { x: 760, y: 840 }, size: { width: 120, height: 48 }, label: 'Cross B' },
  { id: 'l', position: { x: 1040, y: 840 }, size: { width: 120, height: 48 }, label: 'Cross C' },
];
const edges: EdgeSpec[] = [
  { id: 'direct', source: 'a', target: 'b', type: 'direct', label: 'direct', labelPlacement: 'above', labelStyle: { color: '#1d4ed8', fontSize: 12 }, style: { stroke: '#2563eb', strokeWidth: 2, arrowHead: { type: 'arrow', size: 14, filled: true } } },
  { id: 'sharp', source: 'c', target: 'd', router: 'orthogonal', connector: 'straight', label: 'sharp corners', labelPlacement: 'above', style: { stroke: '#475569', strokeDasharray: '6 3', arrowHead: { type: 'diamond', size: 14, filled: false } } },
  { id: 'rounded', source: 'e', target: 'f', router: 'orthogonal', connector: 'rounded', label: 'rounded corners', labelPlacement: 'below', labelStyle: { background: '#eff6ff', padding: 4, borderRadius: 4 }, style: { stroke: '#059669', strokeWidth: 2, arrowHead: { type: 'crow-foot', size: 14, filled: false } } },
  { id: 'curve', source: 'g', target: 'h', type: 'bezier', label: 'no arrowhead', style: { stroke: '#9333ea', strokeWidth: 2, arrowHead: { type: 'none', size: 14, filled: false } } },
  { id: 'cross-ad', source: 'i', target: 'l', type: 'direct', style: { stroke: '#0f766e', jumpPoints: { enabled: true, size: 10, detectMode: 'all' } } },
  { id: 'cross-bc', source: 'k', target: 'j', type: 'direct', style: { stroke: '#b91c1c', jumpPoints: { enabled: true, size: 10, detectMode: 'all' } } },
];

const target = typeof document === 'undefined' ? null : document.createElement('div');
if (target) {
  target.style.height = '900px';
  document.body.append(target);
  void renderQwik(target, <GrafloriaFlow defaultNodes={nodes} defaultEdges={edges} />);
}
```
```tsx title="React"
import { GrafloriaFlow } from '@grafloria/react';
import type { EdgeSpec } from '@grafloria/renderer';

const nodes = [
  { id: 'a', position: { x: 80, y: 80 }, size: { width: 140, height: 56 }, label: 'Direct' },
  { id: 'b', position: { x: 570, y: 150 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'c', position: { x: 80, y: 230 }, size: { width: 140, height: 56 }, label: 'Sharp step' },
  { id: 'd', position: { x: 570, y: 300 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'e', position: { x: 80, y: 380 }, size: { width: 140, height: 56 }, label: 'Rounded step' },
  { id: 'f', position: { x: 570, y: 450 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'g', position: { x: 80, y: 530 }, size: { width: 140, height: 56 }, label: 'Bezier' },
  { id: 'h', position: { x: 570, y: 600 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'i', position: { x: 760, y: 680 }, size: { width: 120, height: 48 }, label: 'Cross A' },
  { id: 'j', position: { x: 1040, y: 680 }, size: { width: 120, height: 48 }, label: 'Cross D' },
  { id: 'k', position: { x: 760, y: 840 }, size: { width: 120, height: 48 }, label: 'Cross B' },
  { id: 'l', position: { x: 1040, y: 840 }, size: { width: 120, height: 48 }, label: 'Cross C' },
];
const edges: EdgeSpec[] = [
  { id: 'direct', source: 'a', target: 'b', type: 'direct', label: 'direct', labelPlacement: 'above', labelStyle: { color: '#1d4ed8', fontSize: 12 }, style: { stroke: '#2563eb', strokeWidth: 2, arrowHead: { type: 'arrow', size: 14, filled: true } } },
  { id: 'sharp', source: 'c', target: 'd', router: 'orthogonal', connector: 'straight', label: 'sharp corners', labelPlacement: 'above', style: { stroke: '#475569', strokeDasharray: '6 3', arrowHead: { type: 'diamond', size: 14, filled: false } } },
  { id: 'rounded', source: 'e', target: 'f', router: 'orthogonal', connector: 'rounded', label: 'rounded corners', labelPlacement: 'below', labelStyle: { background: '#eff6ff', padding: 4, borderRadius: 4 }, style: { stroke: '#059669', strokeWidth: 2, arrowHead: { type: 'crow-foot', size: 14, filled: false } } },
  { id: 'curve', source: 'g', target: 'h', type: 'bezier', label: 'no arrowhead', style: { stroke: '#9333ea', strokeWidth: 2, arrowHead: { type: 'none', size: 14, filled: false } } },
  { id: 'cross-ad', source: 'i', target: 'l', type: 'direct', style: { stroke: '#0f766e', jumpPoints: { enabled: true, size: 10, detectMode: 'all' } } },
  { id: 'cross-bc', source: 'k', target: 'j', type: 'direct', style: { stroke: '#b91c1c', jumpPoints: { enabled: true, size: 10, detectMode: 'all' } } },
];

export default function EdgeStyles() {
  return (
    <div style={{ height: '900px' }}>
      <GrafloriaFlow defaultNodes={nodes} defaultEdges={edges} />
    </div>
  );
}
```
```vue title="Vue"
<script setup lang="ts">
import { GrafloriaFlow } from '@grafloria/vue';
import type { EdgeSpec } from '@grafloria/renderer';

const nodes = [
  { id: 'a', position: { x: 80, y: 80 }, size: { width: 140, height: 56 }, label: 'Direct' },
  { id: 'b', position: { x: 570, y: 150 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'c', position: { x: 80, y: 230 }, size: { width: 140, height: 56 }, label: 'Sharp step' },
  { id: 'd', position: { x: 570, y: 300 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'e', position: { x: 80, y: 380 }, size: { width: 140, height: 56 }, label: 'Rounded step' },
  { id: 'f', position: { x: 570, y: 450 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'g', position: { x: 80, y: 530 }, size: { width: 140, height: 56 }, label: 'Bezier' },
  { id: 'h', position: { x: 570, y: 600 }, size: { width: 140, height: 56 }, label: 'Target' },
  { id: 'i', position: { x: 760, y: 680 }, size: { width: 120, height: 48 }, label: 'Cross A' },
  { id: 'j', position: { x: 1040, y: 680 }, size: { width: 120, height: 48 }, label: 'Cross D' },
  { id: 'k', position: { x: 760, y: 840 }, size: { width: 120, height: 48 }, label: 'Cross B' },
  { id: 'l', position: { x: 1040, y: 840 }, size: { width: 120, height: 48 }, label: 'Cross C' },
];
const edges: EdgeSpec[] = [
  { id: 'direct', source: 'a', target: 'b', type: 'direct', label: 'direct', labelPlacement: 'above', labelStyle: { color: '#1d4ed8', fontSize: 12 }, style: { stroke: '#2563eb', strokeWidth: 2, arrowHead: { type: 'arrow', size: 14, filled: true } } },
  { id: 'sharp', source: 'c', target: 'd', router: 'orthogonal', connector: 'straight', label: 'sharp corners', labelPlacement: 'above', style: { stroke: '#475569', strokeDasharray: '6 3', arrowHead: { type: 'diamond', size: 14, filled: false } } },
  { id: 'rounded', source: 'e', target: 'f', router: 'orthogonal', connector: 'rounded', label: 'rounded corners', labelPlacement: 'below', labelStyle: { background: '#eff6ff', padding: 4, borderRadius: 4 }, style: { stroke: '#059669', strokeWidth: 2, arrowHead: { type: 'crow-foot', size: 14, filled: false } } },
  { id: 'curve', source: 'g', target: 'h', type: 'bezier', label: 'no arrowhead', style: { stroke: '#9333ea', strokeWidth: 2, arrowHead: { type: 'none', size: 14, filled: false } } },
  { id: 'cross-ad', source: 'i', target: 'l', type: 'direct', style: { stroke: '#0f766e', jumpPoints: { enabled: true, size: 10, detectMode: 'all' } } },
  { id: 'cross-bc', source: 'k', target: 'j', type: 'direct', style: { stroke: '#b91c1c', jumpPoints: { enabled: true, size: 10, detectMode: 'all' } } },
];
</script>

<template>
  <div style="height:900px">
    <GrafloriaFlow :default-nodes="nodes" :default-edges="edges" />
  </div>
</template>
```
:::

The first four rows render four distinct path families. `router: 'orthogonal'` keeps both step routes axis-aligned; changing `connector` from `'straight'` to `'rounded'` changes their corner treatment without changing that routing choice. Each row also renders its own label and marker style. The two lower edges cross, and one draws a small hop at the crossing.

## Place and style labels

Set `label` to put text on an edge. `labelPlacement: 'on'` places it on the line in its own box; `'above'` and `'below'` place it beside the line without that box. `labelStyle` controls the label's color, size, weight, family, and background. In the example, the direct edge's label has blue text and sits above its line, while the rounded route's label has a pale background and sits below.

Labels belong to the edge path: when its route changes, the label follows the route. In the live label demo, drag the label along the wire, then move a node to see the edge and label re-route together.

## Choose edge markers

Set `style.arrowHead` to a built-in marker type. The sample uses `arrow`, `diamond`, and `crow-foot`; `none` explicitly renders no arrowhead. The head stays at the endpoint as the route changes. The live marker demo shows the full built-in set: `arrow`, `open-arrow`, `circle`, `square`, `diamond`, `crow-foot`, `hollow-diamond`, and `one-or-many`, as well as `none`.

## Show crossings

Give crossing edges `style.jumpPoints` with `enabled: true` to draw an arc where a line crosses another. The lower pair in the sample starts in an X, so the owning edge renders a hop. Move a node until the lines no longer cross and the hop disappears; move it back and the hop returns. `size` controls the arc size in pixels, and `detectMode: 'all'` selects all crossings.

## Options used here

| Option | Type | Default | What it does |
| --- | --- | --- | --- |
| `type` | `'direct' \| 'smooth' \| 'orthogonal' \| 'bezier'` | Not specified | Selects a path family. |
| `router` | [`LinkRouterName`](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/grafloria-engine-models-types#linkroutername) | Derived from `type` when unset | Chooses where the line goes. |
| `connector` | [`LinkConnectorName`](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/grafloria-engine-models-types#linkconnectorname) | Derived from `type` when unset | Chooses how the route is drawn. |
| `label` | `string` | Not specified | Adds text to the edge. |
| `labelPlacement` | `'on' \| 'above' \| 'below'` | `'on'` | Places the label on, above, or below the edge. |
| `labelStyle` | [`LabelStyle`](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/grafloria-engine-types-interfaces-b-r#labelstyle) | Not specified | Sets label color, size, weight, family, and background. |
| `style` | `Partial<LinkStyle>` | Not specified | Sets the link's visual style, including stroke and arrowheads. |
| `style.jumpPoints` | `JumpPointConfig` | Disabled unless enabled | Controls edge hops at crossings. `size` defaults to 10 px and `detectMode` to `'all'`. |

These values live on the edge spec; you do not need to reach into the model to style a link. The route and connector answer different questions, so changing the connector does not select a new router. For more routing options and saved bends, see [Route and edit edges](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/route-and-edit-edges).

## Live demos and related pages

- [Edge types](https://grafloria.com/demos/edges/edge-types.html) — [source](https://github.com/grafloria/grafloria/blob/6538c1506102712e4265e25bd8ffbb240b3e5038/demos/edges/edge-types.html)
- [Edge labels](https://grafloria.com/demos/edges/edge-labels.html) — [source](https://github.com/grafloria/grafloria/blob/6538c1506102712e4265e25bd8ffbb240b3e5038/demos/edges/edge-labels.html)
- [Edge markers](https://grafloria.com/demos/edges/edge-markers.html) — [source](https://github.com/grafloria/grafloria/blob/6538c1506102712e4265e25bd8ffbb240b3e5038/demos/edges/edge-markers.html)
- [Jump-overs](https://grafloria.com/demos/edges/jump-overs.html) — [source](https://github.com/grafloria/grafloria/blob/6538c1506102712e4265e25bd8ffbb240b3e5038/demos/edges/jump-overs.html)
- [Route and edit edges](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/route-and-edit-edges)
- [Theme and style diagrams](https://bench-grafloria-6l.atloria.app/p/bench-grafloria-6l-dqcsEdUbfS/developer/theme-and-style-diagrams)
