Comfy-Org / Comfy-Org/ComfyUI_frontend
[Enhancement]: Node widget rendering silently corrupts display when several widgets share the same `name`
- Dominant language
- TypeScript
- Stars
- 2k
- Forks
- 699
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 490
Description
### Context
- ComfyUI version: 0.30.0
- ComfyUI frontend version: 1.47.10, 1.47.12
I ran into this while debugging a custom node with a repeatable "row" UI (several widgets added per row via `node.addWidget(...)` in a loop). Each row reused the same literal string for `name` (e.g. every row's text widget was created as `node.addWidget("text", "value", ...)`), relying on `widgets` being drawn by position rather than by name — which is how the legacy LiteGraph canvas rendering worked, and how several existing custom-node patterns already behave (some read widgets back with `node.widgets.find(w => w.name === "...")`, implying name-based lookup is already a soft convention in the ecosystem, just not an enforced one).
I understand duplicate `name` values were never something the API contract explicitly promised to support, so I don't think this is a "you broke my node" bug — more that a previously-harmless pattern now fails silently in a confusing way.
### What happens now
With node rendering going through the newer Vue-based widgets (as opposed to legacy LiteGraph canvas draw), if several widgets on the same node share an identical `name`, they all end up displaying the same content (that of the first one), even though:
- each widget's underlying `.value` remains independent and correct,
- the serialized `widgets_values`, saved workflow, and anything derived from those values at execution time stay correct per-widget.
Only the on-screen rendering collapses to one shared value, which makes the node impossible to edit correctly (you can't tell which row you're actually interacting with).
This looks consistent with a Vue list keyed by `widget.name` — duplicate keys causing DOM/component reuse across list items — but I haven't dug into the frontend source to confirm.
### Suggestion
Rather than (or in addition to) documenting that widget `name` must be unique per node, it'd be more robust if the Vue widget list didn't silently corrupt the display on a duplicate key — e.g. falling back to `${name}-${index}` internally for the render key while leaving `widget.name` untouched for everything else. That way, older custom nodes relying on the previous positional-rendering behavior degrade gracefully (or at worst show a console warning) instead of silently showing wrong data.
With all that said, maybe this is expected/documented behavior and duplicate names are simply unsupported — in that case a runtime warning (similar to Vue's own "duplicate keys" dev warning) would probably save other custom-node authors the same debugging session.
### Minimal repro
```js
import { app } from "../../scripts/app.js";
app.registerExtension({
name: "test.duplicate.widget.names",
async nodeCreated(node, app) {
if (node.comfyClass !== "TestNode") return;
// Three widgets sharing the SAME internal name, each with a
// different default value — mirrors a common "repeatable row" UI
// pattern (add/remove row buttons, etc.) used by several custom nodes.
for (let i = 0; i < 3; i++) {
node.addWidget("text", "row_value", `row ${i}`, (v) => {
console.log(`row ${i} changed to`, v);
});
}
}
});
```
Expected (or at least: previous behavior): three widgets showing `row 0`, `row 1`, `row 2`.
Actual: all three widgets show `row 0`.
### Workaround (for anyone hitting this)
Give each dynamically-created widget a unique internal `name` (e.g. `row_value_0`, `row_value_1`, ...) and set `widget.label` separately for the displayed text, since the draw/render logic falls back to `label || name` for display. This restores correct per-row rendering without changing what's shown on screen.
Contributor guide
Research direction
Start with the Vue-based widget rendering path described in the issue and trace how node.addWidget entries become rendered list items, focusing on the use of widget.name as a key. Run the minimal repro with three row_value widgets and compare the displayed values with each widget’s underlying value. Done means duplicate names no longer collapse the visible widgets, while widget names and serialized values remain unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, typescript
- Domain
- frontend
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100