A React/Javascript component for viewing database ERD diagrams from DBML and TBLS formats
npm install @dlh.io/dlh-erd-viewer-deuxPopular ERD viewer designed by DLH.io originally to provide a better ERD experience to users of the DLH.io platform to visualize relationships in complicated data sources such as Salesforce.com, Dayforce, Paycor, and other operational systems.
- Connectivity to direct retrieve/update ERD from all Major Databases and Data Warehouse systems
- Support additional schema formats
- Metadata Updating
- Sharing
A React/javascript component for visualizing database Entity-Relationship Diagrams (ERD). Built by the tech team at DLH.io (datalakehouse.io), initially for read-only purposes to share target system data profiles for relationships in data for data/analytics engineers to better understand how to model their data products.
``bash`
npm install @dlh.io/dlh-erd-viewer-deux
`tsx
import { ERDViewer } from '@dlh.io/dlh-erd-viewer-deux';
import '@dlh.io/dlh-erd-viewer-deux/styles.css';
const dbmlSchema =
Table users {
id integer [pk]
username varchar(255) [not null]
email varchar(255) [not null]
}
Table posts {
id integer [pk]
title varchar(255) [not null]
author_id integer [ref: > users.id]
};
function App() {
return (
Props / Properties
We've built a number of properties (prop) to allow a great deal of flexibility in how the component is used. Typically each prop is condition based in the code so that a default value is overriden. $3
| Prop | Type | Description |
|------|------|-------------|
|
format | 'dbml' \| 'tbls' | The schema format of the content |
| content | string | The schema content to parse and display |$3
| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
className | string | '' | Additional CSS class names for the container |
| style | React.CSSProperties | - | Inline styles for the container |
| positions | PositionMetadata | - | Pre-defined table positions for the layout |
| devMode | boolean | false | Enable developer mode with position copying tools |
| draggable | boolean | false | Allow users to drag and reposition tables |
| showMinimap | boolean | true | Show or hide the minimap navigation |
| showInfoPanel | boolean | true | Show or hide the information side panel |
| displayMode | DisplayMode | 'all' | Column display mode: 'all', 'keys', or 'tableOnly' |
| layoutAlgorithm | LayoutAlgorithm | 'default' | Layout algorithm for table positioning |
| reverseAnimationFlow | boolean | false | Reverse the animation flow direction on connector lines |
| tableOnlyConnectionMode | TableOnlyConnectionMode | 'center' | Connection mode when in table-only display |
| toolbarAlignment | PanelAlignment | 'center' | Toolbar position: 'left', 'center', or 'right' |
| infoPaneAlignment | PanelAlignment | 'right' | Info panel position: 'left' or 'right' |
| printExportLogo | string | DLH logo | URL of logo to watermark on exports |
| printExportLogoPosition | WatermarkPosition | 'top-left' | Position of watermark: 'top-left', 'top-right', 'bottom-left', 'bottom-right' |
| theme | ERDViewerTheme | - | Theme overrides via CSS custom properties |$3
| Prop | Type | Description |
|------|------|-------------|
|
onExport | (format: 'png' \| 'pdf') => void | Called when diagram is exported |
| onPositionsChange | (positions: PositionMetadata) => void | Called when table positions change (in devMode or draggable) |
| onTableSelect | (table: Table \| null) => void | Called when a table is selected |
| onColumnSelect | (table: Table \| null, columnName: string \| null) => void | Called when a column is selected |
| onDisplayModeChange | (mode: DisplayMode) => void | Called when display mode changes |
| onLayoutAlgorithmChange | (algorithm: LayoutAlgorithm) => void | Called when layout algorithm changes |Types
$3
Controls which columns are shown in table cards:
`typescript
type DisplayMode = 'all' | 'keys' | 'tableOnly';
`-
'all' - Show all columns
- 'keys' - Show only primary and foreign key columns
- 'tableOnly' - Show only table names (no columns)$3
Controls how tables are automatically positioned:
`typescript
type LayoutAlgorithm = 'default' | 'hierarchical' | 'force' | 'grid' | 'spiral' | 'proximity';
`-
'default' - Dagre-based top-to-bottom layout
- 'hierarchical' - Left-to-right hierarchical layout
- 'force' - Force-directed layout
- 'grid' - Grid pattern layout
- 'spiral' - Spiral pattern layout
- 'proximity' - Groups related tables together$3
`typescript
type PanelAlignment = 'left' | 'center' | 'right';
`$3
`typescript
type WatermarkPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
`$3
Pre-defined positions for tables:
`typescript
interface PositionMetadata {
schemaFormat?: 'dbml' | 'tbls';
capturedAt?: string;
version?: string;
positions: TablePosition[];
}interface TablePosition {
tableName: string;
x: number;
y: number;
}
`CSS Customization
The component uses CSS custom properties (variables) for theming. You can override these in your application's CSS:
`css
:root {
/ Core colors /
--erd-primary: #3b82f6;
--erd-secondary: #64748b;
--erd-background: #ffffff;
--erd-surface: #f8fafc;
--erd-border: #e2e8f0;
--erd-text: #1e293b;
--erd-text-muted: #64748b;
--erd-highlight: #3b82f6; / Key indicators /
--erd-pk: #eab308; / Primary key color /
--erd-fk: #8b5cf6; / Foreign key color /
/ Typography /
--erd-font-family: ui-sans-serif, system-ui, sans-serif;
--erd-font-mono: ui-monospace, monospace;
/ Toolbar /
--erd-toolbar-text: #1e293b;
/ Connector lines /
--erd-edge-color: #64748b;
--erd-edge-highlight-color: #3b82f6;
--erd-animation-color: #3b82f6;
/ Table cards /
--erd-table-header-bg: #3b82f6;
--erd-table-header-text: #ffffff;
--erd-table-column-bg: #ffffff;
--erd-table-column-highlight-bg: #eff6ff;
/ Info panel /
--erd-info-panel-bg: #ffffff;
--erd-info-panel-header-bg: #f8fafc;
}
`$3
You can also pass theme overrides directly to the component via the
theme prop (recommended):`tsx
format="dbml"
content={schema}
theme={{
'--erd-primary': '#10b981',
'--erd-highlight': '#10b981',
'--erd-table-header-bg': '#10b981',
}}
/>
`Examples
$3
`tsx
import { ERDViewer } from '@dlh.io/dlh-erd-viewer-deux';
import '@dlh.io/dlh-erd-viewer-deux/styles.css';function BasicExample() {
const schema =
; return (
);
}
`$3
`tsx
function CustomLayoutExample() {
return (
format="dbml"
content={schema}
layoutAlgorithm="hierarchical"
displayMode="keys"
toolbarAlignment="left"
/>
);
}
`$3
`tsx
function SelectionExample() {
const handleTableSelect = (table) => {
if (table) {
console.log('Selected table:', table.name);
}
}; const handleColumnSelect = (table, columnName) => {
if (table && columnName) {
console.log(
Selected column: ${table.name}.${columnName});
}
}; return (
format="dbml"
content={schema}
onTableSelect={handleTableSelect}
onColumnSelect={handleColumnSelect}
/>
);
}
`$3
`tsx
function ExportExample() {
return (
format="dbml"
content={schema}
printExportLogo="https://example.com/my-logo.png"
printExportLogoPosition="bottom-right"
onExport={(format) => console.log(Exported as ${format})}
/>
);
}
`Developer Mode
Developer mode was built so that we can render the ERD of the specific schema and then:
1. Add metadata such as grouping
2. Reposition the tables to a specific position that best emphasizes the schema/tables as we have an opinion on certain system relationships
3. Capture the positions using the "Capture" button, which can then be added to the meta.json
file for that schema so that the ERD will load with the updated positions and/or groupings as a default perspective.$3
Enable
devMode to capture table and group positions for later use:`tsx
function DevModeExample() {
const handlePositionsChange = (positions) => {
// Save positions to use as the positions prop later
console.log(JSON.stringify(positions, null, 2));
}; return (
format="dbml"
content={schema}
devMode={true}
draggable={true}
onPositionsChange={handlePositionsChange}
/>
);
}
`$3
`tsx
const savedPositions = {
"version": "1.0",
"positions": [
{ "tableName": "customers", "x": 50, "y": 100 },
{ "tableName": "orders", "x": 350, "y": 100 },
{ "tableName": "order_items", "x": 650, "y": 100 },
{ "tableName": "products", "x": 650, "y": 350 },
{ "tableName": "categories", "x": 950, "y": 350 },
{ "tableName": "addresses", "x": 50, "y": 350 }
],
"highlights": [
{
"tableName": "customers",
"borderColor": "#3b82f6",
"headerBackgroundColor": "#dbeafe"
},
{
"tableName": "orders",
"borderColor": "#f59e0b",
"headerBackgroundColor": "#fef3c7"
}
],
"groups": [
{
"id": "core-commerce",
"label": "Core Commerce",
"tables": ["customers", "orders", "order_items"],
"collapsible": false
},
{
"id": "product-catalog",
"label": "Product Catalog",
"tables": ["products", "categories"],
"collapsible": false
}
]
};function PositionedExample() {
return (
format="dbml"
content={schema}
positions={savedPositions}
/>
);
}
`$3
`tsx
function DarkThemeExample() {
return (
format="dbml"
content={schema}
theme={{
'--erd-background': '#1e293b',
'--erd-surface': '#334155',
'--erd-border': '#475569',
'--erd-text': '#f1f5f9',
'--erd-text-muted': '#94a3b8',
'--erd-table-header-bg': '#3b82f6',
'--erd-table-column-bg': '#1e293b',
'--erd-toolbar-text': '#f1f5f9',
}}
/>
);
}
`$3
We enjoy the fruits of what our friends at https://vercel.com/ and the community have done with the https://nextjs.org/ project. We use this framework for our initial testing using the ERDeux Viewer component.For Next.js applications, use dynamic import with SSR disabled:
`tsx
import dynamic from 'next/dynamic';const ERDViewer = dynamic(
() => import('@dlh.io/dlh-erd-viewer-deux').then((mod) => mod.ERDViewer),
{ ssr: false }
);
// Import CSS in your layout or page
import '@dlh.io/dlh-erd-viewer-deux/styles.css';
export default function Page() {
return (
);
}
`Supported Schema Formats
Currently the only schema formats are:
- DBML
- TBLS (json)$3
The component supports DBML (Database Markup Language) format:
`dbml
Table users {
id integer [pk, increment]
username varchar(255) [not null, unique]
email varchar(255) [not null]
created_at timestamp [default: now()]
}Table posts {
id integer [pk, increment]
title varchar(255) [not null]
content text
author_id integer [ref: > users.id]
}
``The component also supports TBLS JSON format for schema documentation.
GNU Lesser General Public License (LGPL)