Skip to content

feat(Tooltip): allow offset prop to accept Coordinate object#6868

Merged
ckifer merged 14 commits intorecharts:mainfrom
bigsaigon333:feat/6643
Jan 12, 2026
Merged

feat(Tooltip): allow offset prop to accept Coordinate object#6868
ckifer merged 14 commits intorecharts:mainfrom
bigsaigon333:feat/6643

Conversation

@bigsaigon333
Copy link
Contributor

@bigsaigon333 bigsaigon333 commented Jan 11, 2026

Description

Allow the offset prop of the Tooltip component to accept either a number or a Coordinate object ({ x: number, y: number }). This enables specifying different horizontal and vertical offsets independently.

Changes:

  • Extended offset prop type from number to number | Coordinate in Tooltip and TooltipBoundingBox
  • Split internal offsetTopLeft parameter into separate offsetLeft and offsetTop in the translate utility
  • Updated Storybook and API documentation to reflect the new type

Related Issue

closes #6643

Motivation and Context

Currently, the offset prop only accepts a single number that applies equally to both x and y axes. Users want to position tooltips with different offsets per axis (e.g., 20px horizontal offset but 0px vertical offset). This change allows offset={{ x: 20, y: 0 }} to achieve that.

How Has This Been Tested?

  • Added unit tests for getTooltipTranslate with different offsetTop and offsetLeft values
  • Added unit tests for TooltipBoundingBox with Coordinate type offset (number, object with different x/y, negative values)
  • Added unit tests for Tooltip offset positioning with zero value edge cases (offset=0, offset={ x: 0, y: 10 }, offset={ x: 10, y: 0 })
  • All existing tests pass
npm test -- test/util/tooltip/translate.spec.ts test/component/TooltipBoundingBox.spec.tsx test/component/Tooltip/Tooltip.offset.spec.tsx

Screenshots (if appropriate):

N/A

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

    • Tooltip offset now accepts either a single number or a coordinate object, enabling uniform or per-axis horizontal/vertical offsets.
  • Documentation

    • API docs and storybook descriptions updated to explain numeric vs coordinate offset behavior, negative offsets, and default value.
  • Tests

    • Added and expanded tests covering numeric offsets, distinct x/y coordinate offsets, and negative-offset scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 11, 2026

Walkthrough

The PR widens the Tooltip offset prop to number | Coordinate (per-axis { x, y }), updates types/docs, adjusts translation utilities and bounding-box rendering to accept separate horizontal/vertical offsets, and adds/updates tests covering numeric, per-axis, and negative offsets.

Changes

Cohort / File(s) Summary
Tooltip component types
src/component/Tooltip.tsx
TooltipProps.offset changed from number to number | Coordinate; JSDoc updated to document number vs Coordinate behavior.
Bounding box rendering
src/component/TooltipBoundingBox.tsx
TooltipBoundingBoxProps.offset now number | Coordinate; derives offsetLeft/offsetTop from numeric or Coordinate and passes both to translation util.
Translation utilities
src/util/tooltip/translate.ts
getTooltipTranslateXY renamed parameter offsetTopLeftoffset; getTooltipTranslate now accepts offsetTop and offsetLeft; call mappings updated.
Docs / Storybook
storybook/stories/API/props/TooltipArgTypes.tsx, www/src/docs/api/TooltipAPI.tsx
Prop descriptions updated to explain numeric offset applies to both axes and Coordinate allows distinct x/y offsets.
Tests
test/component/TooltipBoundingBox.spec.tsx, test/component/Tooltip/Tooltip.offset.spec.tsx, test/util/tooltip/translate.spec.ts
Added/updated tests for numeric offsets, per-axis { x, y }, and negative/mixed offsets; test expectations updated to reflect separate offsetTop/offsetLeft behavior.

Sequence Diagram(s)

sequenceDiagram
  participant App as Client/App
  participant Tooltip as Tooltip component
  participant BB as TooltipBoundingBox
  participant Util as translate util
  participant DOM as Browser DOM

  App->>Tooltip: render with offset (number or {x,y})
  Tooltip->>BB: pass position and offset
  BB->>Util: compute translate(offsetLeft, offsetTop, position, viewBox)
  Util-->>BB: return transform(x, y) and flags
  BB->>DOM: apply transform / render tooltip at computed coords
  DOM-->>App: tooltip visible
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • PavelVanecek
  • ckifer
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: extending the Tooltip offset prop to accept Coordinate objects in addition to numbers.
Description check ✅ Passed The description covers all required template sections: clear description of changes, related issue #6643, motivation and context, testing approach with specific test files, types of changes marked correctly, and checklist items completed.
Linked Issues check ✅ Passed The PR fully addresses issue #6643 by extending the offset prop to accept a Coordinate object {x, y}, enabling independent horizontal and vertical offsets as requested.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the offset feature: type updates, internal utility refactoring, documentation updates, and comprehensive test additions. No unrelated modifications detected.

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

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bbd1206 and 3e88bef.

📒 Files selected for processing (1)
  • test/component/Tooltip/Tooltip.offset.spec.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/component/Tooltip/Tooltip.offset.spec.tsx

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.

Comment on lines +34 to +37
type: {
summary: 'number | Coordinate',
detail: 'number | { x: number, y: number }',
},
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I couldn't find a way to support both number and object types in Storybook's control tab at the same time. Also, it seems like other props with object types don't get edited properly either. Am I missing something here?

image

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think number alone is fine, it's a bit of a pain to set objects in Storybook anyway. We have direct code editor + stackblitz for people who want to dig deeper.

Copy link
Contributor Author

@bigsaigon333 bigsaigon333 Jan 11, 2026

Choose a reason for hiding this comment

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

Makes sense. Simplified the type to just number! cf60b97

Copy link
Contributor Author

@bigsaigon333 bigsaigon333 Jan 11, 2026

Choose a reason for hiding this comment

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

It looks like this:

image

Copy link
Collaborator

Choose a reason for hiding this comment

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

Please don't edit this file directly, it's autogenerated. Put the comments into Tooltip.tsx JSDoc and then run npm run omnidoc

Copy link
Contributor Author

@bigsaigon333 bigsaigon333 Jan 11, 2026

Choose a reason for hiding this comment

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

Thanks for the heads up! I wasn't aware this file was autogenerated. Updated the JSDoc in Tooltip.tsx and regenerated with omnidoc. 4ffd9d0

image

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: 0

🧹 Nitpick comments (1)
test/component/TooltipBoundingBox.spec.tsx (1)

63-78: Consider verifying actual offset behavior.

The tests successfully verify that the component renders with different offset types (numeric, Coordinate with distinct values, negative Coordinate). However, they don't verify that the offsets are correctly applied to the tooltip positioning.

💡 Optional enhancement to verify offset behavior

Consider adding assertions that check the computed CSS transform or position to ensure the offset values are correctly applied. You could:

  1. Mock getBoundingClientRect to return specific dimensions (as per the test helper in test/helper/MockGetBoundingClientRect.ts)
  2. Assert on the style.transform or CSS classes applied to the tooltip wrapper

This would provide stronger assurance that the offset logic works correctly beyond just rendering.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a6747e and 063c2b3.

📒 Files selected for processing (7)
  • src/component/Tooltip.tsx
  • src/component/TooltipBoundingBox.tsx
  • src/util/tooltip/translate.ts
  • storybook/stories/API/props/TooltipArgTypes.tsx
  • test/component/TooltipBoundingBox.spec.tsx
  • test/util/tooltip/translate.spec.ts
  • www/src/docs/api/TooltipAPI.tsx
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{ts,tsx}: Never use any type (implicit or explicit) in TypeScript code
Prefer unknown over any and refine the type in TypeScript
Type function parameters and return values explicitly in TypeScript, do not rely on implicit any or inference; exceptions are React components and trivial functions
Do not use as type assertions in TypeScript; the only exception is as const

All imports from recharts must use the public API entry point (e.g., import { TooltipIndex } from 'recharts'). Imports from internal paths like recharts/types/* or recharts/src/* are not allowed and will fail the linter.

Files:

  • src/component/TooltipBoundingBox.tsx
  • www/src/docs/api/TooltipAPI.tsx
  • test/util/tooltip/translate.spec.ts
  • src/component/Tooltip.tsx
  • test/component/TooltipBoundingBox.spec.tsx
  • storybook/stories/API/props/TooltipArgTypes.tsx
  • src/util/tooltip/translate.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Ensure code lints by running npm run lint and follows Airbnb's Style Guide

Files:

  • src/component/TooltipBoundingBox.tsx
  • www/src/docs/api/TooltipAPI.tsx
  • test/util/tooltip/translate.spec.ts
  • src/component/Tooltip.tsx
  • test/component/TooltipBoundingBox.spec.tsx
  • storybook/stories/API/props/TooltipArgTypes.tsx
  • src/util/tooltip/translate.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not hardcode any strings or formatting choices in library code; users should provide localized strings as desired

Files:

  • src/component/TooltipBoundingBox.tsx
  • src/component/Tooltip.tsx
  • src/util/tooltip/translate.ts
test/**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Aim for 100% unit test code coverage when writing new code

Files:

  • test/util/tooltip/translate.spec.ts
  • test/component/TooltipBoundingBox.spec.tsx
test/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (test/README.md)

test/**/*.{test,spec}.{ts,tsx}: Aim for 100% unit test code coverage when writing new code
Prefer to use the createSelectorTestCase helper function when writing or modifying tests
Use the expectLastCalledWith helper function instead of expect(spy).toHaveBeenLastCalledWith(...) for better typing and autocompletion
Verify the number of selector calls using the spy object from createSelectorTestCase to spot unnecessary re-renders and improve performance
Mock getBoundingClientRect in tests using the helper function provided in test/helper/MockGetBoundingClientRect.ts
Use vi.useFakeTimers() in all tests due to Redux autoBatchEnhancer dependency on timers and requestAnimationFrame
Call vi.runOnlyPendingTimers() to advance timers after renders when not using createSelectorTestCase helper, and avoid vi.runAllTimers() to prevent infinite loops
Use userEvent.setup({ advanceTimers: vi.runOnlyPendingTimers }) or the userEventSetup helper function from test/helper/userEventSetup.ts when creating userEvent instances
When testing tooltips on hover, use vi.runOnlyPendingTimers() after each userEvent.hover() call or use the showTooltip helper function from tooltipTestHelpers.ts to account for requestAnimationFrame delays

Files:

  • test/util/tooltip/translate.spec.ts
  • test/component/TooltipBoundingBox.spec.tsx
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

When running unit tests, prefer to run a single test file using npm run test -- path/to/TestFile.spec.tsx rather than running all tests with npm test

Unit tests should be placed in the test directory, with some tests also allowed in www/test. Test files follow the naming convention *.spec.tsx.

Files:

  • test/util/tooltip/translate.spec.ts
  • test/component/TooltipBoundingBox.spec.tsx
test/component/**/*.spec.tsx

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use React Testing Library for testing component interactions and behavior upon rendering

Files:

  • test/component/TooltipBoundingBox.spec.tsx
🧠 Learnings (10)
📚 Learning: 2025-11-23T13:30:10.395Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6669
File: www/src/docs/exampleComponents/ScatterChart/ScatterChartWithLabels.tsx:2-2
Timestamp: 2025-11-23T13:30:10.395Z
Learning: The `TooltipIndex` type from recharts is defined in `src/state/tooltipSlice.ts` but is not currently exported from the public API entry points. It should not be imported from `recharts/types/state/tooltipSlice` as this is an internal implementation path. An ESLint rule is needed to prevent regressions.

Applied to files:

  • src/component/TooltipBoundingBox.tsx
  • www/src/docs/api/TooltipAPI.tsx
  • test/util/tooltip/translate.spec.ts
  • src/component/Tooltip.tsx
  • test/component/TooltipBoundingBox.spec.tsx
  • storybook/stories/API/props/TooltipArgTypes.tsx
  • src/util/tooltip/translate.ts
📚 Learning: 2025-12-14T13:58:49.197Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6771
File: src/shape/Curve.tsx:39-40
Timestamp: 2025-12-14T13:58:49.197Z
Learning: In the recharts codebase, hooks like useAppSelector and other hooks (e.g., useChartLayout()) return undefined when used outside Redux Provider context, instead of throwing. This enables components that call these hooks, such as Curve, to operate in standalone mode by falling back to prop values. During code reviews, ensure TSX files gracefully handle undefined results from hooks and implement fallbacks (e.g., via default props or explicit prop-based values) rather than assuming the hook is always within Provider.

Applied to files:

  • src/component/TooltipBoundingBox.tsx
  • src/component/Tooltip.tsx
📚 Learning: 2026-01-06T22:33:55.414Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6855
File: www/src/docs/api/AreaChartAPI.tsx:422-438
Timestamp: 2026-01-06T22:33:55.414Z
Learning: In Recharts v3, components can render inside any chart type as long as the parent provides the necessary cartesian context (e.g., AreaChart, BarChart, ComposedChart, LineChart, ScatterChart). This means API/tests describing cross-chart compatibility should reflect that Funnel-like components can render under multiple chart parents when Cartesian context is available. When reviewing code or docs, verify that the parent chart supplies the required context and that embedding is intentional for all relevant chart types; update tests/docs to avoid assuming stricter parent-child limitations from Recharts v2.

Applied to files:

  • www/src/docs/api/TooltipAPI.tsx
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : When testing tooltips on hover, use `vi.runOnlyPendingTimers()` after each `userEvent.hover()` call or use the `showTooltip` helper function from `tooltipTestHelpers.ts` to account for requestAnimationFrame delays

Applied to files:

  • test/util/tooltip/translate.spec.ts
  • test/component/TooltipBoundingBox.spec.tsx
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Mock `getBoundingClientRect` in tests using the helper function provided in `test/helper/MockGetBoundingClientRect.ts`

Applied to files:

  • test/util/tooltip/translate.spec.ts
  • test/component/TooltipBoundingBox.spec.tsx
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Verify the number of selector calls using the spy object from `createSelectorTestCase` to spot unnecessary re-renders and improve performance

Applied to files:

  • test/util/tooltip/translate.spec.ts
  • test/component/TooltipBoundingBox.spec.tsx
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Prefer to use the `createSelectorTestCase` helper function when writing or modifying tests

Applied to files:

  • test/util/tooltip/translate.spec.ts
📚 Learning: 2025-12-26T15:59:11.254Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: DEVELOPING.md:0-0
Timestamp: 2025-12-26T15:59:11.254Z
Learning: Applies to test-vr/**/*.spec.ts : Visual regression tests should follow the naming convention `*.spec.ts` and be placed in the `test-vr` directory. When updating snapshots, new files created in `test-vr/__snapshots__` should be committed to the repository.

Applied to files:

  • test/util/tooltip/translate.spec.ts
📚 Learning: 2025-11-25T01:22:59.729Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-25T01:22:59.729Z
Learning: Applies to test/component/**/*.spec.tsx : Use React Testing Library for testing component interactions and behavior upon rendering

Applied to files:

  • test/component/TooltipBoundingBox.spec.tsx
📚 Learning: 2025-12-16T08:12:06.809Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6783
File: test/util/ChartUtils.spec.tsx:15-16
Timestamp: 2025-12-16T08:12:06.809Z
Learning: In tests (files under any test directory, e.g., test/, __tests__/, etc.), allow importing internal module paths (e.g., ../../src/...) and do not require imports to use the public API entry point (src/index.ts). The public API import restriction should apply only to non-test code. During reviews, accept internal imports in test files and enforce the public API pattern only for non-test code.

Applied to files:

  • test/component/TooltipBoundingBox.spec.tsx
🧬 Code graph analysis (4)
src/component/TooltipBoundingBox.tsx (2)
src/util/types.ts (1)
  • Coordinate (128-131)
src/util/tooltip/translate.ts (1)
  • getTooltipTranslate (106-168)
test/util/tooltip/translate.spec.ts (1)
src/util/tooltip/translate.ts (2)
  • getTooltipTranslateXY (33-88)
  • getTooltipTranslate (106-168)
src/component/Tooltip.tsx (2)
src/util/types.ts (1)
  • Coordinate (128-131)
src/index.ts (1)
  • Coordinate (138-138)
test/component/TooltipBoundingBox.spec.tsx (1)
src/component/TooltipBoundingBox.tsx (2)
  • render (78-149)
  • TooltipBoundingBox (39-150)
🔇 Additional comments (11)
src/component/Tooltip.tsx (1)

183-183: LGTM! Type extension is backward compatible.

The offset prop type has been successfully extended from number to number | Coordinate, enabling per-axis offset control while maintaining backward compatibility with existing numeric offsets.

storybook/stories/API/props/TooltipArgTypes.tsx (1)

26-40: LGTM! Clear and comprehensive documentation.

The updated offset documentation clearly explains both usage patterns (numeric and Coordinate) with appropriate detail. The type summary and detail fields provide helpful guidance for users.

src/util/tooltip/translate.ts (2)

33-88: LGTM! Clean refactor enabling per-axis offsets.

The refactor from offsetTopLeft to separate offset parameter (passed as offsetLeft and offsetTop from the caller) correctly enables independent horizontal and vertical offset handling. The arithmetic for both positive and negative offsets is correct.


106-168: LGTM! Consistent parameter naming.

The signature update to use separate offsetTop and offsetLeft parameters aligns well with the refactored getTooltipTranslateXY function. The call sites correctly map these to the offset parameter.

www/src/docs/api/TooltipAPI.tsx (1)

250-267: LGTM! Comprehensive and user-friendly documentation.

The updated offset prop documentation clearly explains both usage patterns with appropriate detail. The explanation distinguishes between numeric (uniform) and Coordinate (per-axis) offsets, complete with a concrete code example.

src/component/TooltipBoundingBox.tsx (3)

23-23: LGTM! Type signature enables per-axis offset control.

The updated type signature correctly allows offset to be either a uniform numeric offset or a Coordinate object with independent x and y values, maintaining backward compatibility while enabling the new feature.


99-101: LGTM! Clean type guard ensures backward compatibility.

The extraction logic correctly handles both the legacy numeric offset (applied uniformly to both axes) and the new Coordinate form (with independent x and y values). The typeof check is type-safe and maintains backward compatibility.


105-106: LGTM! Correctly passes per-axis offsets to translate utility.

The separate offsetLeft and offsetTop parameters align with the refactored getTooltipTranslate signature and enable independent horizontal and vertical positioning.

test/util/tooltip/translate.spec.ts (3)

18-18: LGTM! Parameter rename aligns with refactored signature.

The consistent update from offsetTopLeft to offset in all getTooltipTranslateXY test cases correctly reflects the function signature refactoring while maintaining test coverage.

Also applies to: 35-35, 50-50, 65-65, 80-80, 97-97, 112-112, 129-129, 146-146, 163-163


259-260: LGTM! Existing tests updated for refactored signature.

The split of offsetTopLeft into separate offsetTop and offsetLeft parameters (both set to 0) correctly maintains existing test coverage while adapting to the new function signature.

Also applies to: 272-273, 285-286, 298-299, 315-316, 330-331, 348-349


360-394: LGTM! Excellent test coverage for per-axis offset feature.

The new test cases provide comprehensive coverage of the independent offset functionality:

  • Different positive offsetTop and offsetLeft values
  • Mixed negative/positive offsets

Transform calculations are correct and verify that each axis applies its respective offset independently.

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 for the PR! I have two requests for changes please, then we're good to merge

Copy link
Collaborator

Choose a reason for hiding this comment

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

Please don't edit this file directly, it's autogenerated. Put the comments into Tooltip.tsx JSDoc and then run npm run omnidoc

describe('offset prop', () => {
it('should accept number offset', () => {
render(<TooltipBoundingBox {...defaultProps} offset={15} />);
expect(screen.getByText('Hello world!')).toBeInTheDocument();
Copy link
Collaborator

Choose a reason for hiding this comment

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

We need better assertions here - please look at what other tests are doing, there's showTooltip + mockGetBoundingClientRect + expectTooltipCoordinate helpers available.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, I wasn't aware of those helper functions. Thanks for letting me know!

I've added tests for the actual tooltip positioning with offset in e5e774b.

As for this test, it's essentially just verifying that offset accepts Coordinate type, which TypeScript already covers. I'm thinking of removing it - what do you think?

Comment on lines +34 to +37
type: {
summary: 'number | Coordinate',
detail: 'number | { x: number, y: number }',
},
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think number alone is fine, it's a bit of a pain to set objects in Storybook anyway. We have direct code editor + stackblitz for people who want to dig deeper.

@codecov
Copy link

codecov bot commented Jan 11, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.98%. Comparing base (0a6747e) to head (c6561d2).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6868   +/-   ##
=======================================
  Coverage   93.98%   93.98%           
=======================================
  Files         539      539           
  Lines       53121    53128    +7     
  Branches     5158     5160    +2     
=======================================
+ Hits        49924    49931    +7     
  Misses       3188     3188           
  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
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: 0

🧹 Nitpick comments (2)
test/component/Tooltip/Tooltip.offset.spec.tsx (2)

32-50: Consider adding edge case test for offset=0.

The numeric offset tests are correct and well-documented. However, consider adding a test for offset=0 to ensure the tooltip appears at the exact data point position without any offset.

📝 Optional edge case test
     it('should position tooltip at { x: 20, y: 40 } with offset=20', () => {
       const { container } = renderTestCase(20);
       showTooltipOnCoordinate(container, lineChartMouseHoverTooltipSelector, { clientX: 20, clientY: 20 });
       expectTooltipCoordinate(container, { x: 20, y: 40 });
     });
+
+    it('should position tooltip at { x: 0, y: 20 } with offset=0', () => {
+      const { container } = renderTestCase(0);
+      showTooltipOnCoordinate(container, lineChartMouseHoverTooltipSelector, { clientX: 20, clientY: 20 });
+      expectTooltipCoordinate(container, { x: 0, y: 20 });
+    });
   });

52-58: LGTM! Consider additional edge cases.

The Coordinate offset test correctly validates per-axis offset behavior. Optionally, consider adding tests where one axis has zero offset (e.g., { x: 0, y: 10 } or { x: 10, y: 0 }) to ensure each axis is handled independently.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 063c2b3 and bbd1206.

📒 Files selected for processing (4)
  • src/component/Tooltip.tsx
  • storybook/stories/API/props/TooltipArgTypes.tsx
  • test/component/Tooltip/Tooltip.offset.spec.tsx
  • www/src/docs/api/TooltipAPI.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/component/Tooltip.tsx
  • storybook/stories/API/props/TooltipArgTypes.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{ts,tsx}: Never use any type (implicit or explicit) in TypeScript code
Prefer unknown over any and refine the type in TypeScript
Type function parameters and return values explicitly in TypeScript, do not rely on implicit any or inference; exceptions are React components and trivial functions
Do not use as type assertions in TypeScript; the only exception is as const

All imports from recharts must use the public API entry point (e.g., import { TooltipIndex } from 'recharts'). Imports from internal paths like recharts/types/* or recharts/src/* are not allowed and will fail the linter.

Files:

  • test/component/Tooltip/Tooltip.offset.spec.tsx
  • www/src/docs/api/TooltipAPI.tsx
test/**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Aim for 100% unit test code coverage when writing new code

Files:

  • test/component/Tooltip/Tooltip.offset.spec.tsx
test/component/**/*.spec.tsx

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use React Testing Library for testing component interactions and behavior upon rendering

Files:

  • test/component/Tooltip/Tooltip.offset.spec.tsx
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Ensure code lints by running npm run lint and follows Airbnb's Style Guide

Files:

  • test/component/Tooltip/Tooltip.offset.spec.tsx
  • www/src/docs/api/TooltipAPI.tsx
test/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (test/README.md)

test/**/*.{test,spec}.{ts,tsx}: Aim for 100% unit test code coverage when writing new code
Prefer to use the createSelectorTestCase helper function when writing or modifying tests
Use the expectLastCalledWith helper function instead of expect(spy).toHaveBeenLastCalledWith(...) for better typing and autocompletion
Verify the number of selector calls using the spy object from createSelectorTestCase to spot unnecessary re-renders and improve performance
Mock getBoundingClientRect in tests using the helper function provided in test/helper/MockGetBoundingClientRect.ts
Use vi.useFakeTimers() in all tests due to Redux autoBatchEnhancer dependency on timers and requestAnimationFrame
Call vi.runOnlyPendingTimers() to advance timers after renders when not using createSelectorTestCase helper, and avoid vi.runAllTimers() to prevent infinite loops
Use userEvent.setup({ advanceTimers: vi.runOnlyPendingTimers }) or the userEventSetup helper function from test/helper/userEventSetup.ts when creating userEvent instances
When testing tooltips on hover, use vi.runOnlyPendingTimers() after each userEvent.hover() call or use the showTooltip helper function from tooltipTestHelpers.ts to account for requestAnimationFrame delays

Files:

  • test/component/Tooltip/Tooltip.offset.spec.tsx
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

When running unit tests, prefer to run a single test file using npm run test -- path/to/TestFile.spec.tsx rather than running all tests with npm test

Unit tests should be placed in the test directory, with some tests also allowed in www/test. Test files follow the naming convention *.spec.tsx.

Files:

  • test/component/Tooltip/Tooltip.offset.spec.tsx
🧠 Learnings (12)
📓 Common learnings
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6669
File: www/src/docs/exampleComponents/ScatterChart/ScatterChartWithLabels.tsx:2-2
Timestamp: 2025-11-23T13:30:10.395Z
Learning: The `TooltipIndex` type from recharts is defined in `src/state/tooltipSlice.ts` but is not currently exported from the public API entry points. It should not be imported from `recharts/types/state/tooltipSlice` as this is an internal implementation path. An ESLint rule is needed to prevent regressions.
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : When testing tooltips on hover, use `vi.runOnlyPendingTimers()` after each `userEvent.hover()` call or use the `showTooltip` helper function from `tooltipTestHelpers.ts` to account for requestAnimationFrame delays

Applied to files:

  • test/component/Tooltip/Tooltip.offset.spec.tsx
📚 Learning: 2025-11-23T13:30:10.395Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6669
File: www/src/docs/exampleComponents/ScatterChart/ScatterChartWithLabels.tsx:2-2
Timestamp: 2025-11-23T13:30:10.395Z
Learning: The `TooltipIndex` type from recharts is defined in `src/state/tooltipSlice.ts` but is not currently exported from the public API entry points. It should not be imported from `recharts/types/state/tooltipSlice` as this is an internal implementation path. An ESLint rule is needed to prevent regressions.

Applied to files:

  • test/component/Tooltip/Tooltip.offset.spec.tsx
  • www/src/docs/api/TooltipAPI.tsx
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Mock `getBoundingClientRect` in tests using the helper function provided in `test/helper/MockGetBoundingClientRect.ts`

Applied to files:

  • test/component/Tooltip/Tooltip.offset.spec.tsx
📚 Learning: 2025-12-16T08:12:06.809Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6783
File: test/util/ChartUtils.spec.tsx:15-16
Timestamp: 2025-12-16T08:12:06.809Z
Learning: In tests (files under any test directory, e.g., test/, __tests__/, etc.), allow importing internal module paths (e.g., ../../src/...) and do not require imports to use the public API entry point (src/index.ts). The public API import restriction should apply only to non-test code. During reviews, accept internal imports in test files and enforce the public API pattern only for non-test code.

Applied to files:

  • test/component/Tooltip/Tooltip.offset.spec.tsx
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Verify the number of selector calls using the spy object from `createSelectorTestCase` to spot unnecessary re-renders and improve performance

Applied to files:

  • test/component/Tooltip/Tooltip.offset.spec.tsx
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Prefer to use the `createSelectorTestCase` helper function when writing or modifying tests

Applied to files:

  • test/component/Tooltip/Tooltip.offset.spec.tsx
📚 Learning: 2025-11-25T01:22:59.729Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-25T01:22:59.729Z
Learning: Applies to test/component/**/*.spec.tsx : Use React Testing Library for testing component interactions and behavior upon rendering

Applied to files:

  • test/component/Tooltip/Tooltip.offset.spec.tsx
📚 Learning: 2025-11-25T01:23:14.977Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T01:23:14.977Z
Learning: Applies to src/**/*.{ts,tsx} : Do not hardcode any strings or formatting choices in library code; users should provide localized strings as desired

Applied to files:

  • www/src/docs/api/TooltipAPI.tsx
📚 Learning: 2025-12-26T15:59:11.254Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: DEVELOPING.md:0-0
Timestamp: 2025-12-26T15:59:11.254Z
Learning: Applies to **/*.{ts,tsx} : All imports from `recharts` must use the public API entry point (e.g., `import { TooltipIndex } from 'recharts'`). Imports from internal paths like `recharts/types/*` or `recharts/src/*` are not allowed and will fail the linter.

Applied to files:

  • www/src/docs/api/TooltipAPI.tsx
📚 Learning: 2026-01-06T22:33:55.414Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6855
File: www/src/docs/api/AreaChartAPI.tsx:422-438
Timestamp: 2026-01-06T22:33:55.414Z
Learning: In Recharts v3, components can render inside any chart type as long as the parent provides the necessary cartesian context (e.g., AreaChart, BarChart, ComposedChart, LineChart, ScatterChart). This means API/tests describing cross-chart compatibility should reflect that Funnel-like components can render under multiple chart parents when Cartesian context is available. When reviewing code or docs, verify that the parent chart supplies the required context and that embedding is intentional for all relevant chart types; update tests/docs to avoid assuming stricter parent-child limitations from Recharts v2.

Applied to files:

  • www/src/docs/api/TooltipAPI.tsx
📚 Learning: 2026-01-11T06:13:55.304Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6869
File: www/src/docs/api/useXAxisDomainAPI.tsx:6-20
Timestamp: 2026-01-11T06:13:55.304Z
Learning: In API documentation for hooks (e.g., useXAxisDomainAPI), it's acceptable to describe a parameter like xAxisId using both its literal value (0) and the constant name (defaultAxisId). The description can reference the literal to aid readability, while the defaultVal or equivalent should point to the constant name to aid maintainability. Ensure consistency across similar docs and clearly explain both perspectives for developers using the API.

Applied to files:

  • www/src/docs/api/TooltipAPI.tsx
🧬 Code graph analysis (1)
test/component/Tooltip/Tooltip.offset.spec.tsx (4)
test/helper/mockGetBoundingClientRect.ts (1)
  • mockGetBoundingClientRect (34-42)
test/helper/createSelectorTestCase.tsx (1)
  • createSelectorTestCase (78-139)
test/component/Tooltip/tooltipTestHelpers.tsx (2)
  • showTooltipOnCoordinate (78-85)
  • expectTooltipCoordinate (172-178)
test/component/Tooltip/tooltipMouseHoverSelectors.ts (1)
  • lineChartMouseHoverTooltipSelector (26-26)
🔇 Additional comments (4)
www/src/docs/api/TooltipAPI.tsx (1)

251-268: LGTM! Clear and accurate documentation.

The type expansion to Coordinate | number is backward compatible, and the description clearly explains both usage modes.

test/component/Tooltip/Tooltip.offset.spec.tsx (3)

9-12: Verify that fake timers are set up correctly.

The coding guidelines require calling vi.useFakeTimers() in all tests due to Redux autoBatchEnhancer dependency on timers and requestAnimationFrame. While createSelectorTestCase internally handles vi.runOnlyPendingTimers(), it doesn't set up fake timers.

Verify that the tests run correctly without fake timers. If they fail or are flaky, add the setup:

 describe('Tooltip offset', () => {
+  beforeAll(() => {
+    vi.useFakeTimers();
+  });
+
+  afterAll(() => {
+    vi.useRealTimers();
+  });
+
   beforeEach(() => {
     mockGetBoundingClientRect({ width: 10, height: 10 });
   });

As per coding guidelines: "Use vi.useFakeTimers() in all tests due to Redux autoBatchEnhancer dependency on timers and requestAnimationFrame"


14-30: LGTM! Well-structured test helper.

The renderTestCase helper correctly uses React.ComponentProps for type extraction and properly integrates with createSelectorTestCase.


60-66: LGTM! Excellent coverage of negative offset values.

The test correctly validates negative offset behavior, which is important for positioning tooltips in opposite directions.

@bigsaigon333
Copy link
Contributor Author

32-50: Consider adding edge case test for offset=0.

The numeric offset tests are correct and well-documented. However, consider adding a test for offset=0 to ensure the tooltip appears at the exact data point position without any offset.

Added tests for offset=0, offset={ x: 0, y: 10 }, and offset={ x: 10, y: 0 } edge cases! 3e88bef

@ckifer
Copy link
Member

ckifer commented Jan 12, 2026

thanks @bigsaigon333

@ckifer ckifer dismissed PavelVanecek’s stale review January 12, 2026 17:49

requested changes were made

@ckifer ckifer merged commit 8bb7d65 into recharts:main Jan 12, 2026
39 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.

[Feature request] [Tooltip] offset prop should accept an object with separate { x, y } offsets

3 participants