Skip to content

Labels

Labels are visual elements attached to edges that can display text, buttons, or any custom content. They automatically position themselves along the edge path and follow the edge as it moves or changes shape.

Each edge has a measuredLabels property that provides information about its labels and their computed position and size. This property is read-only and should not be modified.

To display a label on a default edge, add a label property to the edge’s data. You can also control the label position by setting the positionOnEdge data property (defaults to 0.5 — centered).


29 collapsed lines
import '@angular/compiler';
import { Component } from '@angular/core';
import {
initializeModel,
NgDiagramBackgroundComponent,
NgDiagramComponent,
provideNgDiagram,
type NgDiagramConfig,
} from 'ng-diagram';
@Component({
imports: [NgDiagramComponent, NgDiagramBackgroundComponent],
providers: [provideNgDiagram()],
template: `
<div class="not-content diagram">
<ng-diagram [model]="model" [config]="config">
<ng-diagram-background />
</ng-diagram>
</div>
`,
styles: `
.diagram {
display: flex;
height: var(--ng-diagram-height);
border: var(--ng-diagram-border);
}
`,
})
export class DiagramComponent {
config = {
zoom: {
zoomToFit: {
onInit: true,
padding: 120,
},
},
} satisfies NgDiagramConfig;
model = initializeModel({
metadata: {
viewport: { x: 0, y: 0, scale: 0.88 },
},
nodes: [
{
id: '1',
position: { x: 150, y: 150 },
data: { label: 'Node 1' },
rotatable: true,
},
{ id: '2', position: { x: 500, y: 150 }, data: { label: 'Node 2' } },
],
edges: [
{
id: '1',
source: '1',
sourcePort: 'port-right',
targetPort: 'port-left',
target: '2',
data: { label: 'Label', positionOnEdge: 0.3 },
},
],
});
}

Default labels can be styled using CSS variables. You can customize these in your global styles:

ng-diagram-default-edge-label {
--edge-label-padding: 10px;
--edge-label-border-radius: 8px;
--edge-label-font-size: 14px;
--edge-label-background-color: #f3f4f6;
--edge-label-text-color: #1e293b;
--edge-label-border-width: 2px;
--edge-label-border-color: #334155;
--edge-label-border-transition: border-color 0.1s ease-in-out;
}

Available CSS variables:

  • --edge-label-padding - Label padding
  • --edge-label-border-radius - Label border radius
  • --edge-label-font-size - Label font size
  • --edge-label-background-color - Label background color
  • --edge-label-text-color - Label text color
  • --edge-label-border-width - Label border width
  • --edge-label-border-color - Label border color
  • --edge-label-border-color-hover - Label border color while the edge is hovered
  • --edge-label-border-color-selected - Label border color while the edge is selected
  • --edge-label-border-transition - Transition for border changes

The default label also uses these semantic variables that map to the design system:

  • --ngd-default-edge-label-color - Label text color
  • --ngd-default-edge-label-background-color - Label background color
  • --ngd-default-edge-label-border-color - Label border color

The default edge applies different styles to labels based on the edge state (normal, hover, selected). You can customize these styles by modifying the following CSS:

ng-diagram-base-edge.default-edge:hover:not(.selected) {
--edge-label-border-color: #2563eb;
}
ng-diagram-base-edge.default-edge.selected {
--edge-label-border-color: #3b82f6;
}

To display a custom label on an edge, use the NgDiagramBaseEdgeLabelComponent in an implementation of your custom edge component:


import { Component, input } from '@angular/core';
import {
NgDiagramBaseEdgeComponent,
NgDiagramBaseEdgeLabelComponent,
type Edge,
type NgDiagramEdgeTemplate,
} from 'ng-diagram';
@Component({
selector: 'custom-label-edge',
template: `<ng-diagram-base-edge
[edge]="edge()"
stroke="var(--ngd-default-edge-stroke)"
>
<ng-diagram-base-edge-label [id]="'custom-label'" [positionOnEdge]="0.5">
<div class="custom-label">Custom Label</div>
</ng-diagram-base-edge-label>
</ng-diagram-base-edge>`,
styleUrl: './custom-label-edge.component.scss',
imports: [NgDiagramBaseEdgeComponent, NgDiagramBaseEdgeLabelComponent],
})
export class CustomLabelEdgeComponent implements NgDiagramEdgeTemplate {
edge = input.required<Edge>();
}

To give a custom edge the same label look as the default edge, wrap your content in NgDiagramDefaultEdgeLabelComponent since v1.3.0 instead of copying its styles:

<ng-diagram-base-edge [edge]="edge()">
<ng-diagram-base-edge-label [id]="'edge-label'" [positionOnEdge]="0.5">
<ng-diagram-default-edge-label>{{ label() }}</ng-diagram-default-edge-label>
</ng-diagram-base-edge-label>
</ng-diagram-base-edge>

The two elements have separate jobs: ng-diagram-base-edge-label places the label along the edge path and measures it, while ng-diagram-default-edge-label only gives the content its look.

The chip keeps the theme colors, responds to the CSS variables listed above, and highlights its border while the edge is hovered or selected — the same states as in the default edge. Use --edge-label-border-color-hover and --edge-label-border-color-selected to change the highlight colors.

The positionOnEdge property determines where the label appears along the edge path. Labels automatically follow the edge path, regardless of the used routing algorithm.

A number between 0 and 1 places the label at a percentage along the path. 0 is the source, 1 is the target, and 0.5 is the midpoint.

<!-- At the midpoint of the edge -->
<ng-diagram-base-edge-label [id]="'mid'" [positionOnEdge]="0.5">
<span>Midpoint</span>
</ng-diagram-base-edge-label>

A string with a px suffix places the label at a fixed pixel distance along the path. Positive values measure from the source, negative values measure from the target.

<!-- 30px from the source -->
<ng-diagram-base-edge-label [id]="'src'" [positionOnEdge]="'30px'">
<span>Near Source</span>
</ng-diagram-base-edge-label>
<!-- 20px from the target -->
<ng-diagram-base-edge-label [id]="'tgt'" [positionOnEdge]="'-20px'">
<span>Near Target</span>
</ng-diagram-base-edge-label>

Absolute values are clamped to the path length — '500px' on a 300px edge resolves to the target end, and '-500px' resolves to the source end.

ValueModeMeaning
0.5Relative50% along the path (midpoint)
0RelativeAt the source
1RelativeAt the target
'30px'Absolute30px from the source along the path
'-20px'Absolute20px from the target along the path
'0px'AbsoluteAt the source
'-0px'AbsoluteAt the target

ngDiagram automatically measures label dimensions using a ResizeObserver. Measurements update automatically when:

  • A label’s content changes size
  • The positionOnEdge property is updated

If you alter a label’s layout through CSS in a way that doesn’t trigger a size change, call invalidateMeasurements() since v1.2.3 to force re-measurement. await it since v1.3.0 when you need the fresh measuredLabels right away:

await this.ngDiagramService.invalidateMeasurements({
edges: [{ edgeId: 'edge-1' }],
});

See Port Measurement for more details on when this is needed.

Labels can be added and modified dynamically. One way to achieve this is by using diagram’s model. The ModifiableLabelEdgeComponent (see below) shows how to map such data into an actual label implementation.

Click on an edge to select it in the example below. Then fill the label’s name and click “Set Label”.


import '@angular/compiler';
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import {
initializeModel,
NgDiagramBackgroundComponent,
NgDiagramComponent,
NgDiagramEdgeTemplateMap,
provideNgDiagram,
type NgDiagramConfig,
} from 'ng-diagram';
import { LabelPanel } from './label-panel.component';
import { ModifiableLabelEdgeComponent } from './modifiable-label-edge.component';
@Component({
selector: 'diagram',
imports: [
NgDiagramComponent,
FormsModule,
LabelPanel,
NgDiagramBackgroundComponent,
],
providers: [provideNgDiagram()],
template: `
<div class="not-content diagram">
<ng-diagram
[model]="model"
[edgeTemplateMap]="edgeTemplateMap"
[config]="config"
>
<ng-diagram-background />
</ng-diagram>
<label-panel />
</div>
`,
styles: `
.diagram {
position: relative;
display: flex;
height: var(--ng-diagram-height);
border: var(--ng-diagram-border);
}
`,
})
export class DiagramComponent {
edgeTemplateMap = new NgDiagramEdgeTemplateMap([
['modifiable-label', ModifiableLabelEdgeComponent],
]);
config = {
zoom: {
zoomToFit: {
onInit: true,
padding: [50, 170, 50, 50],
},
},
} satisfies NgDiagramConfig;
model = initializeModel({
nodes: [
{
id: 'a',
position: { x: 75, y: 25 },
data: { label: 'Node 1' },
rotatable: true,
},
{ id: 'b', position: { x: 550, y: 175 }, data: { label: 'Node 2' } },
{ id: 'c', position: { x: 75, y: 375 }, data: { label: 'Node 3' } },
],
edges: [
{
id: '1',
source: 'a',
sourcePort: 'port-right',
targetPort: 'port-left',
target: 'b',
type: 'modifiable-label',
data: {
texts: [],
},
},
{
id: '2',
source: 'b',
sourcePort: 'port-left',
targetPort: 'port-right',
target: 'c',
type: 'modifiable-label',
data: {
texts: [],
},
},
],
});
}

When adding interactive elements like inputs to edge labels, dragging on these elements might trigger unwanted diagram behaviors. You can control this using special data attributes:

  • data-no-pan="true" - Prevents the diagram canvas from panning when the user clicks and drags on the element
  • data-no-drag="true" - Prevents nodes from being dragged when the user clicks and drags on the element
<!-- Input in edge label that won't trigger diagram interactions -->
<input type="text" data-no-pan="true" data-no-drag="true" placeholder="Type here" />

NgDiagram supports multiple labels and they can be used to display images, shapes, or any other content. The example below demonstrates how to add multiple labels to an edge to create a flow animation.


7 collapsed lines
import { Component, computed, input } from '@angular/core';
import {
NgDiagramBaseEdgeComponent,
NgDiagramBaseEdgeLabelComponent,
type Edge,
type NgDiagramEdgeTemplate,
} from 'ng-diagram';
const LABEL_COUNT = 10;
const ANIMATION_DURATION = 0.5;
@Component({
selector: 'multi-label-edge',
template: `<ng-diagram-base-edge
[edge]="edge()"
routing="bezier"
[stroke]="selected() ? 'rebeccapurple' : 'var(--ngd-default-edge-stroke)'"
>
@for (label of animatedLabels(); track label.id) {
<ng-diagram-base-edge-label
class="label"
[id]="label.id"
[positionOnEdge]="label.positionOnEdge"
[style]="label.style"
>
</ng-diagram-base-edge-label>
}
</ng-diagram-base-edge>`,
styles: `
@keyframes label-animation {
0% {
background: aliceblue;
}
100% {
background: rebeccapurple;
}
}
.label {
width: 1rem;
height: 1rem;
border-radius: 100%;
background: aliceblue;
animation: label-animation ${ANIMATION_DURATION}s ease-in-out infinite;
}
`,
imports: [NgDiagramBaseEdgeComponent, NgDiagramBaseEdgeLabelComponent],
})
export class MultipleLabelsEdgeComponent implements NgDiagramEdgeTemplate<MultiLabelEdgeData> {
edge = input.required<Edge<MultiLabelEdgeData>>();
selected = computed(() => this.edge().selected);
animatedLabels = computed(() => {
return Array.from({ length: LABEL_COUNT }, (_, i) => ({
id: `label-${i}`,
positionOnEdge: (i + 1) / (LABEL_COUNT + 1),
style: {
animationDelay: `${(ANIMATION_DURATION / LABEL_COUNT) * i}s`,
},
}));
});
}
type MultiLabelEdgeData = {
label: string;
};