diagrams-js
diagrams-js/custom-nodes
coreCreating nodes with external icons using Custom() function. Support for remote URLs (browsers), local files (Node.js), and data URLs. Customize appearance with shape, width, height, margin options. Async icon loading with automatic injection into SVG output.
This skill builds on diagrams-js/getting-started. Read it first for foundational concepts.
diagrams-js — Custom Nodes
Create nodes with custom icons from URLs, local files, or data URLs. Useful for services not in standard providers or proprietary components.
Setup
import { Diagram, Custom } from "diagrams-js";
const diagram = Diagram("Custom Services");
// Remote URL
const service = diagram.add(Custom("My Service", "https://example.com/icon.png"));
const svg = await diagram.render();Core Patterns
Remote URL Icon
import { Diagram, Custom } from "diagrams-js";
const diagram = Diagram("External Services");
const rabbitmq = diagram.add(Custom("Message Queue", "https://example.com/rabbitmq.png"));
const redis = diagram.add(Custom("Cache", "https://example.com/redis.png"));
rabbitmq.to(redis);Local File Icon (Node.js only)
import { Diagram, Custom } from "diagrams-js";
const diagram = Diagram("Local Services");
const service = diagram.add(Custom("Internal API", "./assets/internal-api.png"));Data URL Icon
import { Diagram, Custom } from "diagrams-js";
const diagram = Diagram("Embedded Icons");
const iconData = "data:image/png;base64,iVBORw0KGgo...";
const service = diagram.add(Custom("Service", iconData));Custom Node Options
const node = diagram.add(
Custom("Service", "https://example.com/icon.png", {
shape: "box",
width: "1.2",
height: "1.2",
fixedsize: "true",
margin: "0.1,0.1",
labelloc: "b",
imagescale: "true",
}),
);With Clusters
const diagram = Diagram("Services");
const external = diagram.cluster("External Services");
const stripe = external.add(Custom("Stripe", "https://example.com/stripe.png"));
const twilio = external.add(Custom("Twilio", "https://example.com/twilio.png"));
stripe.to(twilio);Common Mistakes
HIGH Using local file path in browser
Wrong:
// In browser
const node = Custom("Service", "./local/icon.png");
// Fails: Browser cannot access local file systemCorrect:
// In browser - use remote URL or data URL
const node = Custom("Service", "https://example.com/icon.png");
// Or embed as data URL
const node = Custom("Service", "data:image/png;base64,...");Browser cannot access local file system. Use remote URLs, data URLs, or load file server-side and pass data URL.
Source: docs/guides/custom-nodes.mdx
MEDIUM Not handling icon load failure
Wrong:
const node = diagram.add(Custom("Service", "https://bad-url/icon.png"));
// Icon silently missing if fetch failsCorrect:
// Check browser console for warnings
// Or pre-load icon and use data URL
async function loadIcon(url) {
const response = await fetch(url);
const blob = await response.blob();
return new Promise((resolve) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(blob);
});
}
const iconData = await loadIcon("https://example.com/icon.png");
const node = diagram.add(Custom("Service", iconData));Remote icon fetch can fail (CORS, 404, network). Check console warnings or pre-load as data URL.
Source: source code - Custom.ts _fetchRemoteIcon()
See also
- diagrams-js/browser-integration — Browser-specific considerations
- diagrams-js/nodejs-integration — Local file access in Node.js