Originally published on the Grafloria engineering blog.
Two of the most-viewed custom-node questions on Stack Overflow — "Can you pass props to a custom node?" (9.7k views) and "saving additional data to a node after it has been created" (25k views) — are really one question asked from two directions: who owns a node's data? Get that model wrong and every read and write becomes a mystery.
The mental model
A node has exactly one data home: the data dictionary on the node itself, in the diagram's model. Your component doesn't receive "props you passed" — it receives the node's data, and updating means writing to the node, not to a component. Once that clicks, every framework binding is the same pattern wearing local idiom:
// The spec — identical in all three frameworks:
{ id: 'a', type: 'card', position: { x: 80, y: 90 },
size: { width: 230, height: 110 },
data: { title: 'Build', owner: 'CI' } } // ← the one data home
React — a component per type via nodeTypes, receiving
{ id, data, selected, node } (mark the spec custom: true):
function Card({ data, selected }) {
return {data.title};
}
Vue — a named slot per type; declaring the slot is the opt-in:
{{ data.title }}
Angular — an ng-template per type, same auto-opt-in:
{{ data['title'] }}
And the 25k-view question: writing data later
Because the node owns its data, "saving additional data after creation" is a write to the node — tracked for undo and events like any other model change:
const node = instance.getModel().getNode('a');
node.setData('status', 'passing'); // undoable, observable, serialized
instance.renderNow();
No syncing a parallel store, no cloning the nodes array to smuggle a field in. The escape hatch is symmetric: your component/template also receives the live
node, so reads that outgrow data have somewhere to go.
Deep guides per framework: React · Vue · Angular · plain JavaScript.
Grafloria is an MIT-licensed diagram engine for React, Angular, Vue and plain JavaScript — grafloria.com. If this post was useful, the demo gallery is where the ideas live as running code.
Top comments (0)