Skip to content
D
Documentation

Build ER and UML diagrams

how-to
3 min readUpdated

Use a diagram kit when your input is a schema or a typed class model: the kit creates the cards, ports, relationship markers, and routing, while the normal diagram binding mounts the result.

Before you start

Install the package for your binding and the element kit. For plain JavaScript, install the renderer and engine peers too:

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

The examples use JavaScript, Angular, Qwik, React, and Vue. Give the host a resolved height; otherwise the canvas has no space to paint. See Style a diagram for host sizing.

Build an entity-relationship diagram

erDiagram takes entities and optional relationships and returns a spec for render. Each entity becomes an HTML table card. Its columns show their names and types, and pk and fk mark keys. Relationships render as orthogonal edges with crow's-foot cardinality.

JavaScript

Mount the returned spec into a sized element. render returns the live DiagramInstance; fitView() frames the cards after they mount.

js
import { render, erDiagram } from '@grafloria/element';

const host = document.getElementById('diagram');
if (!host) throw new Error('Missing #diagram');
host.style.height = '600px';

const spec = erDiagram({
  entities: [
    { id: 'CUSTOMER', name: 'Customer', position: { x: 60, y: 76 }, columns: [
      { name: 'id', type: 'int', pk: true }, { name: 'email', type: 'varchar' },
    ] },
    { id: 'ORDER', name: 'Order', position: { x: 400, y: 76 }, columns: [
      { name: 'id', type: 'int', pk: true }, { name: 'customer_id', type: 'int', fk: true },
    ] },
  ],
  relationships: [{ from: 'CUSTOMER', to: 'ORDER', label: 'places', cardinality: 'one-to-many' }],
});

const instance = render(spec, host);
instance.fitView(40);

You see two table cards joined by a labelled one-to-many relationship. Dragging a card moves its rows and reroutes the edge; clicking a column selects that row and emits the kit's axk:row-select event.

Framework bindings

Create the same kit spec in each framework, then pass it to the binding component. The component mounts the spec on a real diagram instance; the host's 100vh height gives it a drawing area.

ts
import { Component } from '@angular/core';
import { GrafloriaDiagramComponent } from '@grafloria/angular';
import { erDiagram } from '@grafloria/element';

@Component({
  standalone: true,
  imports: [GrafloriaDiagramComponent],
  template: `<grafloria-diagram [spec]="spec" style="display:block; height:100vh" />`,
})
export class CustomerOrdersComponent {
  spec = erDiagram({
    entities: [
      { id: 'CUSTOMER', name: 'Customer', position: { x: 60, y: 76 }, columns: [
        { name: 'id', type: 'int', pk: true }, { name: 'email', type: 'varchar' },
      ] },
      { id: 'ORDER', name: 'Order', position: { x: 400, y: 76 }, columns: [
        { name: 'id', type: 'int', pk: true }, { name: 'customer_id', type: 'int', fk: true },
      ] },
    ],
    relationships: [{ from: 'CUSTOMER', to: 'ORDER', label: 'places', cardinality: 'one-to-many' }],
  });
}

The result is the same in every tab: typed table rows, key badges, and a routed relationship. The binding owns mounting; the kit owns the table-card presentation.

Build a UML class diagram

umlDiagram accepts classes and optional relationships. Attributes and methods become separate compartments. Relationship kind selects UML notation such as inheritance, realization, aggregation, composition, and dependency; multiplicity adds labels at the relationship ends.

js
import { render, umlDiagram } from '@grafloria/element';

const host = document.getElementById('diagram');
if (!host) throw new Error('Missing #diagram');
host.style.height = '600px';

const spec = umlDiagram({
  classes: [
    { id: 'Animal', abstract: true, position: { x: 260, y: 40 }, attributes: ['# name: String'], methods: ['+ speak(): void'] },
    { id: 'Dog', position: { x: 120, y: 280 }, attributes: ['+ breed: String'], methods: ['+ fetch(): void'] },
    { id: 'Owner', position: { x: 420, y: 280 }, attributes: ['+ name: String'], methods: ['+ adopt(p): void'] },
  ],
  relationships: [
    { from: 'Dog', to: 'Animal', kind: 'inheritance' },
    { from: 'Owner', to: 'Dog', kind: 'aggregation', label: 'owns', multiplicity: ['1', '0..*'] },
  ],
});

const instance = render(spec, host);
spec.finalize(instance);
instance.fitView(40);

You see an italic abstract Animal class above Dog and Owner, with attribute and method compartments and UML inheritance and aggregation markers. render() runs the UML spec's finalize() step automatically; an explicit call is optional and idempotent.

Pass the UML spec to each binding as follows. These samples use a small typed model so each framework mounts a visible class diagram.

ts
import { Component } from '@angular/core';
import { GrafloriaDiagramComponent } from '@grafloria/angular';
import { umlDiagram } from '@grafloria/element';

@Component({
  standalone: true,
  imports: [GrafloriaDiagramComponent],
  template: `<grafloria-diagram [spec]="spec" style="display:block; height:100vh" />`,
})
export class AnimalComponent {
  spec = umlDiagram({
    classes: [
      { id: 'Animal', abstract: true, position: { x: 220, y: 40 }, attributes: ['# name: String'], methods: ['+ speak(): void'] },
      { id: 'Dog', position: { x: 220, y: 260 }, attributes: ['+ breed: String'], methods: ['+ fetch(): void'] },
    ],
    relationships: [{ from: 'Dog', to: 'Animal', kind: 'inheritance' }],
  });
}

The bindings mount the returned kit spec and preserve its class compartments and relationship markers.

Editing and options

Set editable: true on either kit when the diagram itself is the editor. In an ER diagram, double-click a table header or column to rename it, use the add-column affordance, or delete a row. Each edit is undoable and field-level relationships remain attached to their columns. rowSelection controls whether clicking a row selects it; rows are selectable by default.

OptionTypeDefaultWhat it does
entitiesErEntitySpec[]requiredDeclares ER table cards and their columns.
relationshipsErRelationshipSpec[]—Declares ER relationships; TABLE.column endpoints pin to rows.
classesUmlClassSpec[]requiredDeclares UML class cards, attributes, and methods.
editablebooleanfalseEnables in-canvas editing for the kit.
rowSelectionbooleantrueEnables column/member row selection.

If you add a custom-node renderer around these diagrams, its initial render runs at mount, not whenever node data changes. Update the DOM that your renderer owns, or use the dashboard widget update and repaint handles when those are the surface you chose.

See it running

  • Table / ER diagram shows typed columns, PK/FK badges, crow's-foot relationships, and row selection.
Table cards show typed rows, PK/FK badges, and routed crow's-foot relationships.
Class cards show name, attribute, and method compartments with UML relationship markers.

For the editable ER surface, see ERD editor. For the complete UML relationship vocabulary, see UML relationships.

Was this page helpful?

Build ER and UML diagrams — Grafloria