LearnNewsExamplesServices
Frontmatter
id9448
titleTreeGrid Component pooling accumulates `is-leaf` class leading to visual bugs
stateClosed
labels
bugaigrid
assigneestobiu
createdAtMar 12, 2026, 12:29 PM
updatedAtMar 12, 2026, 12:31 PM
githubUrlhttps://github.com/neomjs/neo/issues/9448
authortobiu
commentsCount1
parentIssue9404
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMar 12, 2026, 12:31 PM

TreeGrid Component pooling accumulates is-leaf class leading to visual bugs

Closed v12.1.0 bugaigrid
tobiu
tobiu commented on Mar 12, 2026, 12:29 PM

Description

In Neo.grid.column.component.Tree, the updateIconCls() method mutates the class array using cls.push('is-leaf') inside multiple afterSet... hooks (e.g. afterSetIsLeaf, afterSetCollapsed, etc). When multiple configs change simultaneously (e.g., when a grid cell is recycled by the virtual scroller for a different record), updateIconCls() runs synchronously multiple times before the vdom update is flushed.

This causes state classes like is-expanded and is-leaf to be pushed multiple times into the cls array. Later, when the component is recycled again, NeoArray.remove() only removes the first instance of these duplicate classes. This leads to conflicting classes persisting on the DOM node (e.g. <div class="neo-tree-toggle is-leaf is-expanded">), causing folder icons to disappear.

Solution

Use NeoArray.add(cls, ...) instead of cls.push(...) in Tree.mjs to ensure the state classes are unique within the array, preventing the accumulator bug during rapid config updates.

tobiu added the bug label on Mar 12, 2026, 12:29 PM
tobiu added the ai label on Mar 12, 2026, 12:29 PM
tobiu added the grid label on Mar 12, 2026, 12:29 PM
tobiu assigned to @tobiu on Mar 12, 2026, 12:30 PM
tobiu added parent issue #9404 on Mar 12, 2026, 12:30 PM
tobiu referenced in commit 9095a0d - "fix(grid): prevent duplicate state classes in Tree component during pooling (#9448)" on Mar 12, 2026, 12:31 PM
tobiu
tobiu Mar 12, 2026, 12:31 PM

Input from Gemini 3.1 Pro:

✦ The bug was diagnosed and fixed. The issue was that updateIconCls() in src/grid/column/component/Tree.mjs was using .push() on the cls array inside multiple afterSet... hooks. During rapid state changes (e.g. Row Pooling where the same component gets multiple new configs like collapsed and isLeaf), .push() accumulated multiple instances of the state classes. Later, NeoArray.remove() only removes the first instance, leaving stale classes on the DOM node. Replacing .push() with NeoArray.add() ensures only unique classes are kept, fixing the visual glitch in the tree grid.

Test test/playwright/e2e/GridTree.spec.mjs now passes successfully.

tobiu closed this issue on Mar 12, 2026, 12:31 PM
tobiu cross-referenced by #9412 on Mar 12, 2026, 12:41 PM