Skip to content

[TreeView] Fix extra selection event when clicking a collapsed parent item#22249

Merged
michelengelen merged 4 commits into
mui:masterfrom
michelengelen:bugfix/treeview/22244
Jun 30, 2026
Merged

[TreeView] Fix extra selection event when clicking a collapsed parent item#22249
michelengelen merged 4 commits into
mui:masterfrom
michelengelen:bugfix/treeview/22244

Conversation

@michelengelen

Copy link
Copy Markdown
Member

When a parent item was selected while its children were unmounted (unmountOnExit), re-mounting those children would re-trigger selection propagation unconditionally. This caused onSelectedItemsChange to fire a second time even in selection modes where descendant propagation is disabled. The fix guards the re-propagation behind a check for propagationRules.descendants, matching the intent of the original propagation logic.

Fixes #22246

@michelengelen michelengelen self-assigned this Apr 29, 2026
@michelengelen michelengelen added type: bug It doesn't behave as expected. scope: tree view Changes related to the tree view. This includes TreeView, TreeItem. labels Apr 29, 2026
@code-infra-dashboard

code-infra-dashboard Bot commented Apr 29, 2026

Copy link
Copy Markdown

Deploy preview

https://deploy-preview-22249--material-ui-x.netlify.app/

Bundle size

Bundle Parsed size Gzip size
@mui/x-data-grid 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-pro 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-premium 0B(0.00%) 0B(0.00%)
@mui/x-charts 0B(0.00%) 0B(0.00%)
@mui/x-charts-pro 0B(0.00%) 0B(0.00%)
@mui/x-charts-premium 0B(0.00%) 0B(0.00%)
@mui/x-date-pickers 0B(0.00%) 0B(0.00%)
@mui/x-date-pickers-pro 0B(0.00%) 0B(0.00%)
@mui/x-tree-view 🔺+92B(+0.09%) 🔺+18B(+0.06%)
@mui/x-tree-view-pro 🔺+92B(+0.06%) 🔺+27B(+0.05%)
@mui/x-license 0B(0.00%) 0B(0.00%)

Details of bundle changes


Check out the code infra dashboard for more information about this PR.

@LukasTy LukasTy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex GPT 5.4 review

Findings

  1. Medium: The fix still leaves the extra callback path open when selectionPropagation.descendants is passed in single-select mode. The new guard in TreeViewJSXItemsPlugin.ts only checks descendants, but the actual propagation engine only runs when multiSelect is enabled in TreeViewSelectionPlugin.ts. In single-select, the remount path still goes through keepExistingSelection at TreeViewSelectionPlugin.ts, which reads the normalized array form from selectors.ts and can still emit the second array-shaped payload. That also contradicts the documented contract in SimpleTreeView.tsx, which says selectionPropagation only works when multiSelect is true. I would block on adding the multiSelect guard and a regression test for single-select plus selectionPropagation.descendants.

No second correctness issue stood out in the touched slice.

Assumptions
I confirmed the PR diff in an isolated checkout and checked diagnostics on the touched files; both were clean. I could not complete a focused vitest run there because the temporary worktree could not resolve several workspace-linked dependencies, so this is a source-driven review rather than a test-driven one.

Merge Readiness
Merge readiness score: 6/10. The patch likely fixes the reported default case, but I would not merge it until the guard matches the documented multi-select contract.

  1. Extend the remount guard to also require multiSelect.
  2. Add a regression test for SimpleTreeView with single-select plus selectionPropagation.descendants to pin the contract.

@siriwatknp siriwatknp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit on the test

@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been inactive for 30 days. Please remove the stale label or leave a comment to keep it open. Otherwise, it will be closed in 15 days.

@github-actions github-actions Bot added the stale Inactive for 7 days (issues) or 30 days (PRs); closed after 5 or 15 more days if no update. label May 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been closed due to 15 days of inactivity after being marked stale.

@github-actions github-actions Bot closed this Jun 15, 2026
@michelengelen michelengelen reopened this Jun 16, 2026
@github-actions github-actions Bot removed the stale Inactive for 7 days (issues) or 30 days (PRs); closed after 5 or 15 more days if no update. label Jun 16, 2026
@michelengelen
michelengelen requested a review from LukasTy June 29, 2026 07:11

@flaviendelangle flaviendelangle left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR review

This is a focused, correct bug fix for a double-fired onSelectedItemsChange when re-mounting the children of a selected collapsed parent. The added guards (isMultiSelectEnabled + propagationRules.descendants) precisely match the only condition under which re-propagation does meaningful work, and they cannot throw since state.selectionPropagation defaults to EMPTY_OBJECT. Nothing is merge-blocking.

Bugs (0)

No findings. I verified the two guards are both load-bearing and neither over- nor under-restricts:

  • isMultiSelectEnabled is necessary, not redundant. Without it, single-select with selectionPropagation.descendants: true would still call setItemSelection → setSelectedItems, and setSelectedItems always fires onSelectedItemsChange at the end (TreeViewSelectionPlugin.ts:93) even though propagateSelection is skipped — reproducing the double-fire. The new test at the third added case pins exactly this.
  • descendants-only (dropping the implicit parents path) is correct. Re-mounting children of a selected parent can only need to push selection down (descendants). The parents rule only selects a parent from changes.added/changes.removed of children, so for a re-asserted parent with keepExistingSelection it was inert — the old unconditional call did no useful work in parents-only mode (it only double-fired the callback). Skipping it is a behavior improvement, not a regression.
  • No crash risk. selectionSelectors.propagationRules(state) reads state.selectionPropagation, which MinimalTreeViewStore.utils.ts:31 initializes to EMPTY_OBJECT, so .descendants is safely undefined (falsy) when unset.

Tests (0)

No findings. The three added tests cover the regression (single-select, callCount === 1), the preserved legitimate behavior (multiSelect + descendants still propagates to late-mounted children), and the isMultiSelectEnabled-guard case (single-select + descendants).

ℹ️ Optional: there's no test for multiSelect + parents-only on re-mount, which the new condition also stops from double-firing. It's an inert path, so this is a nice-to-have rather than a gap worth blocking on.

Simplifications (0)

No findings.

Docs (0)

No findings. The code comment was correctly updated to explain the multiSelect/descendants intent.

Verdict

Approve — minimal, correct, well-tested fix with passing CI and no behavioral regressions in the parents-propagation or already-selected-descendants paths.


🤖 Review generated with Claude Code

@LukasTy

LukasTy commented Jun 30, 2026

Copy link
Copy Markdown
Member

LGTM, thanks for addressing this. 🙏

GPT 5.4 suggestion

If you want even more regression coverage, a dedicated test for multiSelect: true with descendant propagation disabled would be a nice extra, but I do not consider that a blocker.

@michelengelen
michelengelen merged commit d0af831 into mui:master Jun 30, 2026
21 checks passed
@michelengelen
michelengelen deleted the bugfix/treeview/22244 branch June 30, 2026 09:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: tree view Changes related to the tree view. This includes TreeView, TreeItem. type: bug It doesn't behave as expected.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[tree view][SimpleTreeView] onSelectedItemsChange called with arrays in single-select mode

4 participants