Skip to content

fix(transition): prevent enter if leave is in progress#14443

Merged
edison1105 merged 5 commits intovuejs:mainfrom
Mini-ghost:fix/transition-enter-during-leave
Feb 24, 2026
Merged

fix(transition): prevent enter if leave is in progress#14443
edison1105 merged 5 commits intovuejs:mainfrom
Mini-ghost:fix/transition-enter-during-leave

Conversation

@Mini-ghost
Copy link
Copy Markdown
Contributor

@Mini-ghost Mini-ghost commented Feb 10, 2026

close #12091
close #12133

Link to minimal reproduction

https://play.vuejs.org/#eNrtV19vEzkQ/yqjFVITKdnkKCehXBJxVH24E1BU+sYicDezqYnXtmzvNlGU787Y3t0mECrghSK1D409f3/j+Zdsk3+1TusKk0kytbnh2oFFV+k5PNy/TPJSK+PgZbWEwqgSTtIRnX0cJx3zYtXxLlYNazqKMc4zSReHpRbMId0ApgteQy6YtbMsMUq5LAl04pDp+dQ7aAkXK7rTv6A3IkU6TUd75uhq3Ub4Y+ptwdaLLrglgc0EloYv/vEUfxi2esNciaqUdgIGNTLXezqAksuSrXvjAfxVmH6flHYhimA8GSTO5koWfJl+tkpSDoOfLMlVqblAc6EdV9JmySQi8DwmhLr9P9CcqXDQ0vMbzFdH6J/t2tOy5K1Bi6bGLOl4jpkl0kt59vm7N7imc8cs1aISJH0P8xItxewxRrGXlVwQ7D25gPa/kFEul1f2fO1Q2jYoD9RL7oJ8llCWz+4J/Q7uafos6NF70is2tfNH9sCWqqUYgL0JL3WJBeyauo8l/4Bj+CYkqmVLb3+jbmG2F1GvYMJi/+HhbRELtbSEmBLRe/+h7+lFJXNff6Are9OTrCT4oQyjAkpnNqTx6cnW83Y+f+p29mTrP9KaiQp3n7y4txzvabAUFIMHAF5AsAyz2QxOrrFQBs+lQ3PS+IJgNaqTs/CKbdUfgFTyErWhjsyRWqHXqN/5JuX3HzzpwF5svjiP7puq7dS8rpwjZy9ywfMVDdlDrzRuu6sf7NNRlG+1lWhOdBYc6iGFS0Z6hHIAXC5w3aePADpLYLLCDXEDvRvkQddqJufbrReE3Y6g+3tneSR463DUeZxeGUYzJ4ypRpBpmtCmvb2Ijz+k7GAA1YfZPKb+MC9Z0qkckw20AylWEOWo3cD5jtlhzmSOQuDimIOzlnmg2IQgkNV4NIRXnnOgckw20I6EcEw2cL4ye5cKTTnmBan4oqOUtrv5WvmMvlYLJuBMUUDSTUe6y9pdrn5sPdfxdYeMWqH2W48oAWxDib3gOqsTUJrl3G1gnJ5aQGYxbuU9W37+7ltyKlppNCcw/maRx68ojxvocQP9IRsoVDyzG5nD3h55o0zJxJVaLgX+3B4hIrorXqKqXC9OifuX2ACejccRyC8voH24NGJCNxKjpO+JXFLzFm4Cz7WfN1ESoujjbvql3fS4Yn7rivlYo/G/nGjJnKZ/p0+fJ7svbRhiDQ==

Problem

If the state is toggled back to false during beforeEnter, <Transition> hooks can run in an unexpected order:

beforeEnter → beforeLeave → leave → enter → afterEnter

Result

After this change, the hook sequence becomes:

beforeEnter → beforeLeave → leave → afterLeave

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Resolved an issue where enter transitions could overlap with pending leave transitions, ensuring correct animation sequencing during rapid component state changes.
  • Tests

    • Added end-to-end test coverage for transition hook execution order when enter transitions follow leave transitions.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 10, 2026

📝 Walkthrough

Walkthrough

A guard was added to the transition enter hook to prevent enter from executing when a leave transition is already in progress. An e2e test was added to verify this behavior through hook ordering and DOM state validation.

Changes

Cohort / File(s) Summary
Transition Guard Logic
packages/runtime-core/src/components/BaseTransition.ts
Added early return guard in resolveTransitionHooks.enter to skip enter execution if a leave is currently in progress for the vnode.
E2E Test Coverage
packages/vue/__tests__/e2e/Transition.spec.ts
Added "prevent enter when leaving" test case that toggles component visibility and validates transition hook execution order and final DOM state when enter is prevented during an active leave.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Poem

🐰 A hop, a skip, then pause mid-flight,
No rushing in while leaving's tight,
The guard stands watch with gentle care,
One dance at a time, oh so fair! 🎭

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(transition): prevent enter if leave is in progress' directly and specifically describes the main change: adding a guard in resolveTransitionHooks.enter to prevent overlapping enter while a corresponding leave is pending.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 10, 2026

Size Report

Bundles

File Size Gzip Brotli
runtime-dom.global.prod.js 104 kB (+19 B) 39.3 kB (-2 B) 35.3 kB (-16 B)
vue.global.prod.js 162 kB (+19 B) 59.3 kB (-5 B) 52.7 kB (+22 B)

Usages

Name Size Gzip Brotli
createApp (CAPI only) 47.8 kB 18.6 kB 17.1 kB
createApp 56 kB 21.7 kB 19.8 kB
createSSRApp 60.2 kB 23.4 kB 21.4 kB
defineCustomElement 61.6 kB 23.4 kB 21.4 kB
overall 70.4 kB (+19 B) 27 kB 24.6 kB (-2 B)

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Feb 10, 2026

Open in StackBlitz

@vue/compiler-core

pnpm add https://pkg.pr.new/@vue/compiler-core@14443
npm i https://pkg.pr.new/@vue/compiler-core@14443
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/compiler-dom

pnpm add https://pkg.pr.new/@vue/compiler-dom@14443
npm i https://pkg.pr.new/@vue/compiler-dom@14443
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/compiler-sfc

pnpm add https://pkg.pr.new/@vue/compiler-sfc@14443
npm i https://pkg.pr.new/@vue/compiler-sfc@14443
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/compiler-ssr

pnpm add https://pkg.pr.new/@vue/compiler-ssr@14443
npm i https://pkg.pr.new/@vue/compiler-ssr@14443
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/reactivity

pnpm add https://pkg.pr.new/@vue/reactivity@14443
npm i https://pkg.pr.new/@vue/reactivity@14443
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/runtime-core

pnpm add https://pkg.pr.new/@vue/runtime-core@14443
npm i https://pkg.pr.new/@vue/runtime-core@14443
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/runtime-dom

pnpm add https://pkg.pr.new/@vue/runtime-dom@14443
npm i https://pkg.pr.new/@vue/runtime-dom@14443
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/server-renderer

pnpm add https://pkg.pr.new/@vue/server-renderer@14443
npm i https://pkg.pr.new/@vue/server-renderer@14443
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/shared

pnpm add https://pkg.pr.new/@vue/shared@14443
npm i https://pkg.pr.new/@vue/shared@14443
yarn add https://pkg.pr.new/@vue/[email protected]

vue

pnpm add https://pkg.pr.new/vue@14443
npm i https://pkg.pr.new/vue@14443
yarn add https://pkg.pr.new/[email protected]

@vue/compat

pnpm add https://pkg.pr.new/@vue/compat@14443
npm i https://pkg.pr.new/@vue/compat@14443
yarn add https://pkg.pr.new/@vue/[email protected]

commit: b175f25

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/runtime-core/__tests__/components/BaseTransition.spec.ts`:
- Around line 1245-1251: The test uses setTimeout which lets the callback run
after the test completes, so move to an awaited promise-based delay (or directly
await nextTick if sufficient) so the test waits for the toggle change and
assertions to run synchronously; specifically set toggle.value = true, await the
appropriate async resolution (e.g., await nextTick() or await new Promise(res =>
setTimeout(res))), then assert
expect(hooks.join('-')).toBe('beforeEnter-beforeLeave-leave-afterLeave')—also
replace the non-standard .eq() matcher with .toBe() and ensure you're awaiting
nextTick() after setting toggle.value to properly flush updates.

},

enter(el) {
if (el[isLeavingKey]) return
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.

Image

It has an isLeaving state.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thank you very much. I’ve already updated it.

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.

Thank you for your PR. The fix is correct, but I've made some adjustments. The tests have also been switched to e2e tests because the unit tests' leave completes immediately, which is inconsistent with browser behavior.

@edison1105 edison1105 added scope: transition 🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. wait changes labels Feb 10, 2026
@edison1105 edison1105 changed the title fix(transition): skip enter hook when element is already leaving during mount fix(transition): prevent enter if leave is in progress Feb 11, 2026
@edison1105 edison1105 added ready to merge The PR is ready to be merged. and removed wait changes labels Feb 11, 2026
@edison1105
Copy link
Copy Markdown
Member

/ecosystem-ci run

@vue-bot
Copy link
Copy Markdown
Contributor

vue-bot commented Feb 11, 2026

📝 Ran ecosystem CI: Open

suite result latest scheduled
primevue success success
vue-macros success success
vue-simple-compiler success success
pinia success success
vue-i18n success success
vueuse success success
vitepress success success
radix-vue success success
quasar success success
vant failure success
vite-plugin-vue success success
vuetify success success
router failure failure
nuxt success success
test-utils success success
language-tools success success

@edison1105 edison1105 merged commit df059f8 into vuejs:main Feb 24, 2026
30 of 34 checks passed
@Mini-ghost Mini-ghost deleted the fix/transition-enter-during-leave branch February 24, 2026 06:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. ready to merge The PR is ready to be merged. scope: transition

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Transition enter-cancelled not called on asynchronous rendering

3 participants