Bug: Tooltip gets stuck in open state due to early return when popperTriggers includes 'hover'
While using floating-vue, I encountered an issue where tooltips can get stuck in an open state under certain edge cases. This behavior is similar to what was discussed in #860.
After investigation, I traced the issue to the following code:
main: https://github.com/Akryum/floating-vue/blob/main/packages/floating-vue/src/components/Popper.ts#L477 vue2: https://github.com/Akryum/floating-vue/blob/vue2/packages/floating-vue/src/components/Popper.ts#L451
// Abort if aiming for the popper
if (!skipAiming && this.hasPopperShowTriggerHover && this.$_isAimingPopper()) {
return
}
This early return prevents the execution of any logic below — including both the tooltip close logic and any parent popper state updates. As a result, when $_isAimingPopper() returns true, the tooltip may remain open indefinitely, since no further conditions are evaluated and no close action is triggered.
Analysis
The original intention of checking $_isAimingPopper() is understandable — to avoid hiding the tooltip when the user is moving the cursor toward the popper. However, by returning early here, it skips necessary logic that ensures the tooltip can recover or close later.
Would it be more appropriate to restructure this logic like this?
if (this.parentPopper) {
if (this.hasPopperShowTriggerHover && this.$_isAimingPopper()) {
clearTimeout(this.parentPopper.lockedChildTimer)
this.parentPopper.lockedChildTimer = setTimeout(() => {
if (this.parentPopper.lockedChild === this) {
this.parentPopper.lockedChild.hide({ skipDelay })
this.parentPopper.lockedChild = null
}
}, 1000)
return
}
}
This ensures that even if $_isAimingPopper() returns true, the locking behavior is correctly handled.
Suggestion
Consider moving the $_isAimingPopper() check inside the this.parentPopper condition;
Or refactor the logic to make sure the locking behavior is not bypassed due to early return;
If this behavior is intentional, could you clarify the design purpose and whether a fallback mechanism can be added to recover the tooltip state?
Reproduction
You can refer to the demo linked in the existing issue: https://github.com/Akryum/floating-vue/issues/860
Thanks a lot for maintaining this great library 🙌
Based on my understanding, moving the return condition inside the if (this.parentPopper) block would still allow the tooltip's delay configuration to function as intended. In such a case, the hide() process can still be interrupted if the cursor enters the popper during the delay period — which preserves the expected behavior and does not negatively affect the tooltip's usability.
If my understanding is incorrect, please feel free to clarify — thank you!
Any updates on this?