Skip to content

Close tooltip on blur#6958

Merged
ckifer merged 1 commit intorecharts:mainfrom
gVguy:main
Feb 7, 2026
Merged

Close tooltip on blur#6958
ckifer merged 1 commit intorecharts:mainfrom
gVguy:main

Conversation

@gVguy
Copy link
Contributor

@gVguy gVguy commented Feb 4, 2026

Description

When focus leaves the chart (Tab to next element or blur event), the blurAction is dispatched, which sets the keyboard interaction to inactive, causing the tooltip to disappear.

Pressing Escape still closes tooltips as before.

Related Issue

Closes #6937

Motivation and Context

Solves the problem described in the related issue ^

How Has This Been Tested?

  • All related tests pass, including the new tests that specifically verify this behavior.
  • Checked manually in storybook.

Screenshots (if appropriate):

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • I have added a storybook story or VR test, or extended an existing story or VR test to show my changes

Summary by CodeRabbit

  • New Features

    • Tooltips now automatically close when a chart loses focus, improving keyboard navigation and accessibility across multiple charts
    • Improved focus/blur handling so only the active chart shows its tooltip
  • Tests

    • Added tests covering tooltip behavior for focus/blur interactions and multi-chart keyboard navigation scenarios

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 4, 2026

Walkthrough

Adds blur handling so charts dispatch a blurAction when they lose focus; middleware listens for blurAction and deactivates keyboard interaction state; tests added to verify tooltip closure on blur and keyboard navigation between multiple charts.

Changes

Cohort / File(s) Summary
Keyboard event handling
src/chart/RechartsWrapper.tsx, src/state/keyboardEventsMiddleware.ts
Added blurAction export and middleware listener to handle blur events by setting keyboard interaction active=false. Wired an onBlur handler into RechartsWrapper to dispatch blurAction.
Tests
test/chart/AccessibilityLayer.spec.tsx
Added tests verifying tooltip closes on chart blur and correct tooltip behavior when navigating between multiple charts with keyboard focus.

Sequence Diagram

sequenceDiagram
    participant User
    participant RechartsWrapper
    participant Middleware as keyboardEventsMiddleware
    participant State as AccessibilityState

    User->>RechartsWrapper: focus moves away (blur)
    RechartsWrapper->>Middleware: dispatch blurAction
    Middleware->>Middleware: is accessibility layer active?
    alt active
        Middleware->>State: dispatch setKeyboardInteraction(active: false)
        State->>State: clear activeIndex and activeCoordinate
    end
    Note over RechartsWrapper,State: Tooltip hides due to cleared state
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • ckifer
  • PavelVanecek
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Close tooltip on blur' clearly and concisely summarizes the main change: handling tooltip closure when focus is lost.
Description check ✅ Passed The description covers all required sections including motivation, testing approach, and issue link, with the types of changes checkbox appropriately filled.
Linked Issues check ✅ Passed The PR fully addresses issue #6937 by implementing blur event handling that closes tooltips when focus leaves the chart, matching the expected behavior described in the issue.
Out of Scope Changes check ✅ Passed All changes are directly related to the stated objective of closing tooltips on blur; no unrelated modifications are present in the three files changed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

@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 `@test/chart/AccessibilityLayer.spec.tsx`:
- Around line 202-231: The new test "Tooltip closes when chart loses focus" is
missing fake timers and doesn't use the createSelectorTestCase helper; update
the spec to call vi.useFakeTimers()/vi.restoreAllMocks() in the describe/test
setup (or add beforeAll/afterAll) so timers and requestAnimationFrame are
controlled, and refactor the test to use createSelectorTestCase instead of raw
render (or wrap the render in the helper) so selector-call assertions are
supported—adjust usages of render, act, and arrowRight to the
createSelectorTestCase pattern and ensure timers are advanced where needed
(e.g., vi.advanceTimersByTime) to avoid flakiness.
🧹 Nitpick comments (1)
src/state/keyboardEventsMiddleware.ts (1)

160-178: Add explicit types for the blur listener parameters.

The handler currently relies on inference; please make the parameter and return types explicit for consistency and clarity.

🛠️ Suggested change
-  effect: (_action, listenerApi: ListenerEffectAPI<RechartsRootState, AppDispatch>) => {
+  effect: (
+    _action: ReturnType<typeof blurAction>,
+    listenerApi: ListenerEffectAPI<RechartsRootState, AppDispatch>,
+  ): void => {

As per coding guidelines, type function parameters and return values explicitly.

Comment on lines +202 to +231
test('Tooltip closes when chart loses focus', () => {
const { container } = render(
<AreaChart width={100} height={50} data={PageData} accessibilityLayer={accessibilityLayer}>
<Area type="monotone" dataKey="uv" stroke="#ff7300" fill="#ff7300" />
<Tooltip />
<Legend />
<XAxis dataKey="name" />
<YAxis />
</AreaChart>,
);

const svg = getMainSurface(container);
assertNotNull(svg);
const tooltip = getTooltip(container);

// Tooltip not visible initially
expect(tooltip.textContent).toBe('');

// Focus the chart - tooltip should appear
act(() => svg.focus());
expect(tooltip).toHaveTextContent('Page A');

// Navigate to another data point
arrowRight(svg);
expect(tooltip).toHaveTextContent('Page B');

// Blur the chart - tooltip should disappear
act(() => svg.blur());
expect(tooltip.textContent).toBe('');
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use fake timers (and prefer createSelectorTestCase) in the new tests.

These new tests are added without vi.useFakeTimers(), and they use render directly instead of createSelectorTestCase, which can lead to timer-related flakiness and misses selector-call assertions. Consider adding fake timers for the describes that include these tests and, if feasible, refactor the new cases to createSelectorTestCase.

🧪 Suggested timer setup
 describe.each([true, undefined])('AccessibilityLayer with accessibilityLayer=%s', accessibilityLayer => {
+  beforeEach(() => {
+    vi.useFakeTimers();
+  });
+
+  afterEach(() => {
+    vi.useRealTimers();
+  });
 describe('Multiple charts navigation', () => {
+  beforeEach(() => {
+    vi.useFakeTimers();
+  });
+
+  afterEach(() => {
+    vi.useRealTimers();
+  });

As per coding guidelines, use vi.useFakeTimers() in all tests due to Redux autoBatchEnhancer dependency on timers and requestAnimationFrame, and prefer the createSelectorTestCase helper when writing or modifying tests.

🤖 Prompt for AI Agents
In `@test/chart/AccessibilityLayer.spec.tsx` around lines 202 - 231, The new test
"Tooltip closes when chart loses focus" is missing fake timers and doesn't use
the createSelectorTestCase helper; update the spec to call
vi.useFakeTimers()/vi.restoreAllMocks() in the describe/test setup (or add
beforeAll/afterAll) so timers and requestAnimationFrame are controlled, and
refactor the test to use createSelectorTestCase instead of raw render (or wrap
the render in the helper) so selector-call assertions are supported—adjust
usages of render, act, and arrowRight to the createSelectorTestCase pattern and
ensure timers are advanced where needed (e.g., vi.advanceTimersByTime) to avoid
flakiness.

@codecov
Copy link

codecov bot commented Feb 4, 2026

Codecov Report

❌ Patch coverage is 92.30769% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.38%. Comparing base (196fe3e) to head (c81b1d2).
⚠️ Report is 8 commits behind head on main.

Files with missing lines Patch % Lines
src/state/keyboardEventsMiddleware.ts 90.47% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6958      +/-   ##
==========================================
- Coverage   91.13%   90.38%   -0.75%     
==========================================
  Files         509      515       +6     
  Lines       37967    38522     +555     
  Branches     5288     5342      +54     
==========================================
+ Hits        34601    34818     +217     
- Misses       3357     3695     +338     
  Partials        9        9              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Collaborator

@PavelVanecek PavelVanecek left a comment

Choose a reason for hiding this comment

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

Thanks!

@codecov
Copy link

codecov bot commented Feb 4, 2026

Bundle Report

Changes will decrease total bundle size by 21.24kB (-0.74%) ⬇️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
recharts/bundle-cjs 1.25MB 851 bytes (0.07%) ⬆️
recharts/bundle-es6* 1.07MB -19.37kB (-1.78%) ⬇️
recharts/bundle-umd* 536.16kB -2.72kB (-0.51%) ⬇️

ℹ️ *Bundle size includes cached data from a previous commit

Affected Assets, Files, and Routes:

view changes for bundle: recharts/bundle-cjs

Assets Changed:

Asset Name Size Change Total Size Change (%)
chart/RechartsWrapper.js 144 bytes 15.13kB 0.96%
state/keyboardEventsMiddleware.js 707 bytes 5.86kB 13.71% ⚠️
view changes for bundle: recharts/bundle-umd

Assets Changed:

Asset Name Size Change Total Size Change (%)
Recharts.js -2.72kB 536.16kB -0.51%
view changes for bundle: recharts/bundle-es6

Assets Changed:

Asset Name Size Change Total Size Change (%)
state/selectors/axisSelectors.js -1.52kB 53.26kB -2.78%
util/types.js -1.07kB 8.09kB -11.73%
hooks.js -13.77kB 7.41kB -65.0%
util/getRelativeCoordinate.js -14 bytes 4.28kB -0.33%
index.js -243 bytes 3.45kB -6.58%
util/scale/createCategoricalInverse.js (Deleted) -2.33kB 0 bytes -100.0% 🗑️
state/selectors/combiners/combineInverseScaleFunction.js (Deleted) -421 bytes 0 bytes -100.0% 🗑️

Copy link
Member

Choose a reason for hiding this comment

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

@gVguy can you undo these changes in the lockfile please? I think this is from running an older version of npm

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Undone 👍

@ckifer ckifer merged commit 2ff088a into recharts:main Feb 7, 2026
41 of 42 checks passed
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.

Tooltips don't close with keyboard navigation

3 participants