Skip to content

fix(CTooltip,CPopover): cancel pending delay timers and preserve child handlers#465

Merged
mrholek merged 1 commit into
mainfrom
fix/tooltip-popover-delay-timers
Jun 13, 2026
Merged

fix(CTooltip,CPopover): cancel pending delay timers and preserve child handlers#465
mrholek merged 1 commit into
mainfrom
fix/tooltip-popover-delay-timers

Conversation

@mrholek

@mrholek mrholek commented Jun 13, 2026

Copy link
Copy Markdown
Member

Problem

  1. Delay timer race. handleHide scheduled a setTimeout that was never cancelled. Re-hovering the toggler during the delay.hide window still dismissed a visible tooltip/popover under the cursor. Symmetrically, the show timer kept running after the pointer left, flipping internal _visible state (and aria-describedby on the toggler) for a tooltip that was no longer mounted.
  2. No cleanup on unmount. Pending timers fired after unmount and the Popper instance was never destroyed.
  3. Child handlers overridden. cloneElement replaced the child's own onClick/onFocus/onBlur/onMouseEnter/onMouseLeave instead of composing them — a silent, hard-to-diagnose bug for consumers.

Changes

  • Track the show/hide timeout in a shared ref and clear it on every show/hide transition (the same single-timer approach Bootstrap uses).
  • On re-show while still mounted, schedule the show timer directly since the [mounted] effect won't re-fire.
  • Clear the pending timer and destroy the Popper instance on unmount.
  • Call the cloned child's original event handlers before the tooltip/popover trigger logic; typed the cloned child as ReactElement<HTMLAttributes<HTMLElement>> instead of any (also clears a pre-existing no-explicit-any lint error on these lines).

Tests

5 new regression tests (3 tooltip, 2 popover): re-hover during hide delay keeps it visible, leaving before the show delay cancels the pending show (incl. no stray aria-describedby), and child handlers still fire. All 5 fail against main, pass with the fix. Full suite: 127 suites / 353 tests green, no snapshot changes.

…d handlers

- track the show/hide timeout in a ref and clear it on every show/hide
  transition, so re-hovering during the hide delay no longer dismisses a
  visible tooltip/popover and leaving before the show delay elapses no
  longer flips internal state for an unmounted one
- clear the pending timer and destroy the popper instance on unmount
- compose cloned child event handlers (onClick, onFocus, onBlur,
  onMouseEnter, onMouseLeave) instead of overriding them
@mrholek mrholek merged commit 8cc974e into main Jun 13, 2026
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.

1 participant