Skip to content

fix(splitter): re-initialize panels when child count changes dynamically#8478

Open
YevheniiKotyrlo wants to merge 1 commit intoprimefaces:masterfrom
YevheniiKotyrlo:fix/splitter-dynamic-panels
Open

fix(splitter): re-initialize panels when child count changes dynamically#8478
YevheniiKotyrlo wants to merge 1 commit intoprimefaces:masterfrom
YevheniiKotyrlo:fix/splitter-dynamic-panels

Conversation

@YevheniiKotyrlo
Copy link

@YevheniiKotyrlo YevheniiKotyrlo commented Mar 10, 2026

Defect Fixes

Fixes #8477

Splitter only calls initializePanels() in mounted(). When a SplitterPanel is added dynamically via v-if after mount (e.g., waiting for async data), the new panel never receives a flexBasis style — it renders at its natural flex size (~27%) instead of the configured :size percentage (40%).

PR #6394 added resetState() as a manual workaround, but consumers shouldn't need to call it — the Splitter should handle panel count changes automatically.

Related: #5463 (same root cause — closed with manual resetState workaround)

Problem

<Splitter>
  <SplitterPanel :size="60">Main content</SplitterPanel>
  <SplitterPanel v-if="detailLoaded" :size="40">
    <!-- Appears after async data loads -->
    <!-- Renders at ~27% instead of 40% — no flexBasis applied -->
  </SplitterPanel>
</Splitter>

After this fix, dynamically added panels immediately receive the correct flexBasis:

<Splitter>
  <SplitterPanel :size="60">Main content</SplitterPanel>
  <SplitterPanel v-if="detailLoaded" :size="40">
    <!-- Appears at exactly 40% — flexBasis applied on panel count change -->
  </SplitterPanel>
</Splitter>

Reproducer: bun run patch applies the fix, bun run unpatch reverts.

Root cause

initializePanels() queries this.$el.children for data-pc-name="splitterpanel" elements and sets flexBasis from panel.props.size. The panels computed (which iterates $slots.default()) correctly includes dynamically added panels, but initializePanels() never re-runs — the new DOM element has no flexBasis set.

Changes

packages/primevue/src/splitter/Splitter.vue: Add updated() lifecycle hook that tracks panel count via _lastPanelCount. When the count changes (panel added or removed), re-run initializePanels().

The count guard ensures this does not reset user resize state on every re-render — it only fires when panels are actually added or removed.

Scope / Impact

  • No breaking changes — existing Splitters with static panels are unaffected (count never changes)
  • Minimal change — reuses existing initializePanels(), adds only the updated() hook
  • Fixes all dynamic panel patternsv-if, dynamic components, programmatic panel addition/removal

Verification

Gate Result
StackBlitz reproducer bun run patch applies fix, bun run unpatch reverts
All 3 existing Splitter unit tests PASS
Pressure tests (rapid toggle, remove, stateful, nested) PASS
All CI gates (format, lint, test, build) PASS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Splitter does not initialize panels added dynamically via v-if after mount

1 participant