Entity Relationship Diagrams in EJ2 JavaScript Diagram Control
2 Jul 202624 minutes to read
An Entity Relationship (ER) diagram is a visual representation of a database structure. It displays entities (such as tables), their attributes (such as columns), and the relationships between those entities. In the Syncfusion® Diagram control, ER diagrams can be created by configuring nodes with ErShapeModel and connectors with ErConnectorShapeModel.
ER entity nodes are added to the nodes property, and ER relationships are defined as connectors and added to the connectors property.
ER diagram elements
An ER diagram is built using the following main elements:
- Entities - Represent database tables or objects, such as Customer, Order, or Product.
- Fields - Represent columns or attributes inside an entity, such as CustomerID, Name, or Email.
- Relationships - Represent how one entity is associated with another entity.
Creating ER entity nodes
An ER entity node represents a database entity, such as a table or object. It appears as a box that displays the entity name in the header and its fields as rows. The node shape can be defined by setting the type property to Er.
ej.diagrams.Diagram.Inject(ej.diagrams.ErDiagrams);
// Define a basic ER entity (Customer table)
var customer = {
id: 'Customer',
offsetX: 300,
offsetY: 200,
shape: {
type: 'Er',
header: {
annotation: {
content: 'Customer'
}
},
fields: [
{
id: 'cust_id',
name: 'CustomerID',
dataType: 'INT',
isPrimaryKey: true,
constraints: ['NotNull']
},
{
id: 'cust_firstname',
name: 'FirstName',
dataType: 'VARCHAR(50)',
constraints: ['NotNull']
},
{
id: 'cust_email',
name: 'Email',
dataType: 'VARCHAR(100)',
constraints: ['Unique']
}
]
}
};
// Initialize diagram control
var diagram = new ej.diagrams.Diagram(
{
width: '100%',
height: '400px',
nodes: [customer]
},
'#element'
);<!DOCTYPE html>
<html lang="en">
<head>
<title>EJ2 Diagram</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Typescript UI Controls">
<meta name="author" content="Syncfusion">
<link href="index.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-popups/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-base/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-buttons/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-popups/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-splitbuttons/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-diagrams/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-navigations/styles/tailwind3.css" rel="stylesheet">
<script src="https://cdn.syncfusion.com/ej2/34.1.29/dist/ej2.min.js" type="text/javascript"></script>
</head>
<body style="margin-top: 100px;">
<div id="container">
<div id="element"></div>
</div>
<script>
var ele = document.getElementById('container');
if (ele) {
ele.style.visibility = "visible";
}
</script>
<script src="index.js" type="text/javascript"></script>
</body>
</html>Configure the entity header
The header is the top section of an ER entity node that displays the entity name. The header appearance can be customized using the header property.
| ER Header Property | Description |
|---|---|
| annotation | Defines the text content displayed in the header. |
| height | Defines the height of the header area in pixels. |
| style | Defines style properties such as fill color, text color, and font settings. |
ej.diagrams.Diagram.Inject(ej.diagrams.ErDiagrams);
// Define an ER entity with customized header
var customer = {
id: 'Customer',
offsetX: 300,
offsetY: 200,
shape: {
type: 'Er',
header: {
annotation: {
content: 'CUSTOMER TABLE',
style: {
color: 'white',
fontSize: 13,
bold: true,
fontFamily: 'Arial'
}
},
height: 35,
style: {
fill: '#2E75B6'
}
},
fields: [
{
id: 'cust_id',
name: 'CustomerID',
dataType: 'INT',
isPrimaryKey: true
},
{
id: 'cust_name',
name: 'FirstName',
dataType: 'VARCHAR(50)'
},
{
id: 'cust_email',
name: 'Email',
dataType: 'VARCHAR(100)'
}
]
}
};
// Initialize diagram control
var diagram = new ej.diagrams.Diagram(
{
width: '100%',
height: '400px',
nodes: [customer]
},
'#element'
);<!DOCTYPE html>
<html lang="en">
<head>
<title>EJ2 Diagram</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Typescript UI Controls">
<meta name="author" content="Syncfusion">
<link href="index.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-popups/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-base/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-buttons/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-popups/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-splitbuttons/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-diagrams/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-navigations/styles/tailwind3.css" rel="stylesheet">
<script src="https://cdn.syncfusion.com/ej2/34.1.29/dist/ej2.min.js" type="text/javascript"></script>
</head>
<body style="margin-top: 100px;">
<div id="container">
<div id="element"></div>
</div>
<script>
var ele = document.getElementById('container');
if (ele) {
ele.style.visibility = "visible";
}
</script>
<script src="index.js" type="text/javascript"></script>
</body>
</html>NOTE
If no header is specified, a default header is automatically added to the ER entity node with the default style and height.
Define entity fields
Fields represent the columns or attributes of an entity. They can be defined using the fields property. Each field can display information such as the field name, data type, and key constraints, including primary key, foreign key, unique, and not null.
| ER Field Property | Description |
|---|---|
| id | Defines the unique identifier for the field within the entity. |
| name | Defines the display name of the field. |
| dataType | Defines the data type of the field, such as INT, VARCHAR(255), or BOOLEAN. |
| isPrimaryKey | Indicates whether the field is the primary key of the entity. |
| isForeignKey | Indicates whether the field is a foreign key that references another entity. |
| constraints | Defines additional constraints applied to the field. Accepts one or more ErFieldConstraint values. |
| style | Defines the visual style of the ER field row. Supports standard shape style properties such as fill, stroke color, stroke width, opacity, and other supported diagram style values. Field-level style values override applicable values from field defaults. |
| annotation | Defines text styling for the ER field row. Only annotation style property is applicable. The annotation content property is ignored. |
ej.diagrams.Diagram.Inject(ej.diagrams.ErDiagrams);
// Define an ER entity with various field properties
var product = {
id: 'Product',
offsetX: 300,
offsetY: 200,
shape: {
type: 'Er',
header: {
annotation: {
content: 'Product'
}
},
fields: [
{
id: 'prod_id',
name: 'ProductID',
dataType: 'INT',
isPrimaryKey: true,
constraints: ['NotNull']
},
{
id: 'prod_code',
name: 'ProductCode',
dataType: 'VARCHAR(50)',
constraints: ['NotNull', 'Unique']
},
{
id: 'prod_name',
name: 'ProductName',
dataType: 'VARCHAR(150)',
constraints: ['NotNull']
},
{
id: 'prod_price',
name: 'Price',
dataType: 'DECIMAL(10,2)',
constraints: ['NotNull']
},
{
id: 'prod_desc',
name: 'Description',
dataType: 'TEXT'
},
{
id: 'prod_catid',
name: 'CategoryID',
dataType: 'INT',
isForeignKey: true
}
]
}
};
// Initialize diagram control
var diagram = new ej.diagrams.Diagram(
{
width: '100%',
height: '400px',
nodes: [product]
},
'#element'
);<!DOCTYPE html>
<html lang="en">
<head>
<title>EJ2 Diagram</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Typescript UI Controls">
<meta name="author" content="Syncfusion">
<link href="index.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-popups/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-base/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-buttons/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-popups/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-splitbuttons/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-diagrams/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-navigations/styles/tailwind3.css" rel="stylesheet">
<script src="https://cdn.syncfusion.com/ej2/34.1.29/dist/ej2.min.js" type="text/javascript"></script>
</head>
<body style="margin-top: 100px;">
<div id="container">
<div id="element"></div>
</div>
<script>
var ele = document.getElementById('container');
if (ele) {
ele.style.visibility = "visible";
}
</script>
<script src="index.js" type="text/javascript"></script>
</body>
</html>NOTE
If no fields are specified, a default single field is automatically added to the ER entity node.
Add or remove ER fields at runtime
ER fields can be updated after the diagram is rendered by using the addErField and removeErField methods. These methods help add new fields to an ER entity node or remove existing fields without recreating the diagram.
The addErField method adds a field to an ER entity node.
var entityNode = diagram.nodes[0];
var newField = {
id: 'customer_phone',
name: 'Phone',
dataType: 'VARCHAR(20)'
};
diagram.addErField(entityNode, newField);To insert the field at a specific position, pass the index as the third argument:
diagram.addErField(entityNode, newField, 2);The removeErField method removes an existing field from an ER entity node.
// Find the field that needs to be removed from the ER entity.
var fieldToRemove = entityNode.shape.fields.find(
field => field.id === 'customer_phone'
);
if (fieldToRemove) {
diagram.removeErField(entityNode, fieldToRemove);
}Configure default field appearance
The fieldDefaults property defines the default visual appearance for all fields in an ER entity node. These settings are applied to every field unless they are overridden by individual field-level style settings.
| ER Field Defaults Property | Description |
|---|---|
| alternateRowColors | Defines exactly two colors cycled across field rows in alternating order. Row 0 uses alternateRowColors[0], row 1 uses alternateRowColors[1], row 2 uses alternateRowColors[0], and so on. |
| height | Defines the default height of each ER entity field row. |
Style ER entities and fields
The appearance of ER entities and their fields can be customized using style properties. The node-level style property controls the overall ER entity appearance, while individual field style values can override applicable styles for specific field rows.
ej.diagrams.Diagram.Inject(ej.diagrams.ErDiagrams);
// Define ER entities with custom styling
var customer = {
id: 'Customer',
offsetX: 200,
offsetY: 200,
shape: {
type: 'Er',
header: {
annotation: {
content: 'CUSTOMER TABLE',
style: {
bold: true,
color: 'white'
}
},
height: 35,
style: {
fill: '#2E75B6',
color: 'white',
fontSize: 12,
bold: true
}
},
fields: [
{
id: 'cust_id',
name: 'CustomerID',
dataType: 'INT',
isPrimaryKey: true
},
{
id: 'cust_firstname',
name: 'FirstName',
dataType: 'VARCHAR(50)'
},
{
id: 'cust_email',
name: 'Email',
dataType: 'VARCHAR(100)'
}
],
fieldDefaults: {
alternateRowColors: ['#E7F0F7', '#ffffff']
}
},
style: {
fill: '#ffffff',
strokeColor: '#2E75B6',
strokeWidth: 1
}
};
var product = {
id: 'Product',
offsetX: 600,
offsetY: 200,
shape: {
type: 'Er',
header: {
annotation: {
content: 'PRODUCT CATALOG',
style: {
bold: true,
color: 'white'
}
},
height: 35,
style: {
fill: '#70AD47',
color: 'white',
fontSize: 12,
bold: true
}
},
fields: [
{
id: 'prod_id',
name: 'ProductID',
dataType: 'INT',
isPrimaryKey: true,
style: {
fill: '#FFE699'
}
},
{
id: 'prod_name',
name: 'ProductName',
dataType: 'VARCHAR(150)'
},
{
id: 'prod_price',
name: 'Price',
dataType: 'DECIMAL(10,2)',
style: {
fill: '#C6E0B4'
}
}
],
fieldDefaults: {
alternateRowColors: ['#ffffff', '#F2F2F2']
}
},
style: {
fill: '#ffffff',
strokeColor: '#70AD47',
strokeWidth: 1.5
}
};
// Initialize diagram control
var diagram = new ej.diagrams.Diagram(
{
width: '100%',
height: '400px',
nodes: [customer, product]
},
'#element'
);<!DOCTYPE html>
<html lang="en">
<head>
<title>EJ2 Diagram</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Typescript UI Controls">
<meta name="author" content="Syncfusion">
<link href="index.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-popups/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-base/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-buttons/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-popups/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-splitbuttons/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-diagrams/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-navigations/styles/tailwind3.css" rel="stylesheet">
<script src="https://cdn.syncfusion.com/ej2/34.1.29/dist/ej2.min.js" type="text/javascript"></script>
</head>
<body style="margin-top: 100px;">
<div id="container">
<div id="element"></div>
</div>
<script>
var ele = document.getElementById('container');
if (ele) {
ele.style.visibility = "visible";
}
</script>
<script src="index.js" type="text/javascript"></script>
</body>
</html>NOTE
Field-level styles override applicable node-level and field default styles.
Track entity field changes
The erEntityChanged event is triggered when ER entity fields are added, removed, or reordered. This event provides the previous and updated entity states, which can be used to track modifications, validate field changes, or synchronize updates with an external data source.
erEntityChanged: (args) => {
if (args.cause === 'FieldsReorder' && args.state === 'Completed') {
console.log('ER fields reordered successfully.');
}
}Creating ER relationships
Relationships define how one ER entity is connected to another entity. In the Diagram control, relationships are created using ER connectors. They are rendered as lines with multiplicity symbols at the connector ends.The connector shape can be defined by setting the type property to Er.
| ER Connector Shape Property | Description |
|---|---|
| type | Defines the connector shape type as 'Er'. Default: 'Er'. |
| relationship | Defines whether the relationship is identifying or non-identifying. |
| sourceMultiplicity | Defines the Crow’s Foot multiplicity rendered at the source end of the ER connector. |
| targetMultiplicity | Defines the Crow’s Foot multiplicity rendered at the target end of the ER connector. |
Define relationship multiplicity
Multiplicity defines how many instances of one entity can be associated with instances of another entity. In ER diagrams, multiplicity is represented using Crow’s Foot symbols at the source and target ends of a connector.
| Multiplicity Type | Meaning | Example | Image |
|---|---|---|---|
| One | Represents a single participation marker. | A customer has one primary account. | ![]() |
| OneAndOnlyOne | Represents mandatory participation of exactly one instance. | A user must have exactly one profile. | ![]() |
| Many | Represents multiple instances. | A customer can have many orders. | ![]() |
| ZeroOrOne | Represents zero or one instance. | An employee may have zero or one manager badge. | ![]() |
| OneOrMany | Represents one or more instances. | A department must have one or more employees. | ![]() |
| ZeroOrMany | Represents zero or more instances. | A customer may have zero or more wish list items. | ![]() |
ej.diagrams.Diagram.Inject(ej.diagrams.ErDiagrams);
var customer = {
id: 'Customer',
offsetX: 250,
offsetY: 100,
shape: {
type: 'Er',
header: {
annotation: {
content: 'Customer'
}
},
fields: [
{
id: 'customer_id',
name: 'CustomerID',
dataType: 'INT',
isPrimaryKey: true
}
]
},
style: {
fill: '#ffffff',
strokeColor: '#7c3aed',
strokeWidth: 1.5
}
};
var order = {
id: 'Order',
offsetX: 400,
offsetY: 250,
shape: {
type: 'Er',
header: {
annotation: {
content: 'Order'
}
},
fields: [
{
id: 'order_id',
name: 'OrderID',
dataType: 'INT',
isPrimaryKey: true
},
{
id: 'customer_id_fk',
name: 'CustomerID',
dataType: 'INT',
isForeignKey: true
}
]
},
style: {
fill: '#ffffff',
strokeColor: '#7c3aed',
strokeWidth: 1.5
}
};
var relationship = {
id: 'customer_order',
sourceID: 'Customer',
targetID: 'Order',
shape: {
type: 'Er',
sourceMultiplicity: {
type: 'One'
},
targetMultiplicity: {
type: 'OneOrMany'
}
},
style: {
strokeColor: '#7c3aed',
strokeWidth: 1.5
},
sourceDecorator: {
style: {
strokeColor: '#7c3aed',
strokeWidth: 1.5
}
},
targetDecorator: {
style: {
strokeColor: '#7c3aed',
strokeWidth: 1.5
}
}
};
var diagram = new ej.diagrams.Diagram(
{
width: '100%',
height: '400px',
nodes: [customer, order],
connectors: [relationship],
getConnectorDefaults: (connector) => {
connector.cornerRadius = 10;
connector.type = 'Orthogonal';
return connector;
}
},
'#element'
);<!DOCTYPE html>
<html lang="en">
<head>
<title>EJ2 Diagram</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Typescript UI Controls">
<meta name="author" content="Syncfusion">
<link href="index.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-popups/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-base/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-buttons/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-popups/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-splitbuttons/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-diagrams/styles/tailwind3.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/34.1.29/ej2-navigations/styles/tailwind3.css" rel="stylesheet">
<script src="https://cdn.syncfusion.com/ej2/34.1.29/dist/ej2.min.js" type="text/javascript"></script>
</head>
<body style="margin-top: 100px;">
<div id="container">
<div id="element"></div>
</div>
<script>
var ele = document.getElementById('container');
if (ele) {
ele.style.visibility = "visible";
}
</script>
<script src="index.js" type="text/javascript"></script>
</body>
</html>




