Skip to content

Fix tooltip payload type from any#6925

Merged
ckifer merged 1 commit intomainfrom
tooltip-payload
Jan 27, 2026
Merged

Fix tooltip payload type from any#6925
ckifer merged 1 commit intomainfrom
tooltip-payload

Conversation

@PavelVanecek
Copy link
Collaborator

@PavelVanecek PavelVanecek commented Jan 24, 2026

Description

Changed Tooltip.TooltipContentProps.payload from any to TooltipPayload and it cascaded from there.

Related Issue

Fixes #6564

Motivation and Context

I tried to keep the strict Tooltip generics but they are mostly a lie - there is zero guarantee that the other graphical elements are actually going to provide those types so it was a false sense of security. So I mostly reverted to the basic ValueType and NameType which are unions of the allowed values.

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 items can now be sorted using custom sorter functions or predefined options (dataKey, value, name).
    • Enhanced tooltip formatting with improved control over item display.
  • Chores

    • New type exports added for better type safety and consistency across tooltip components.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 24, 2026

Walkthrough

Added TooltipPayload and TooltipItemSorter types to improve type safety in custom tooltips. Introduced default generic parameters for tooltip types, simplified component signatures, and implemented centralized payload sorting and formatting logic in DefaultTooltipContent. Updated public API exports and example components.

Changes

Cohort / File(s) Summary
Core tooltip type definitions
src/component/DefaultTooltipContent.tsx, src/component/Tooltip.tsx
Added TooltipItemSorter union type enabling preset and custom sorting strategies. Introduced default generic parameters (TValue = ValueType, TName = NameType) for Formatter, Payload, and TooltipProps. Updated Tooltip function signature from generic to concrete type parameters.
Tooltip rendering logic
src/component/DefaultTooltipContent.tsx
Implemented lodashLikeSortBy helper for payload sorting. Centralized formatter resolution and application per entry. Refactored rendering to skip 'none' type entries and compute styles consistently. Changed component signature from generic function component to plain function accepting non-generic Props.
Tooltip content and payload types
src/component/Tooltip.tsx
Changed TooltipContentProps.payload type from ReadonlyArray<any> to TooltipPayload (concrete type). Updated formatter callbacks to accept TooltipPayloadEntry and TooltipPayload instead of generic Payload<TValue, TName>. Centralized tooltipContentProps construction before passing to renderContent.
Public API exports
src/index.ts
Added TooltipPayload export from ./state/tooltipSlice. Added TooltipItemSorter and ValueType as TooltipValueType exports from ./component/DefaultTooltipContent.
Test setup and verification
omnidoc/verifyExamples.spec.ts
Added TooltipItemSorter and TooltipPayload to exportsThatNeedExamples list, requiring examples for these new/updated exports.
Component tests
test/component/DefaultTooltipContent.spec.tsx, test/component/Tooltip/Tooltip.content.spec.tsx, test/component/Tooltip/itemSorter.spec.tsx
Removed explicit generic parameters from TooltipContentProps and DefaultTooltipContentProps type annotations. Updated itemSorter test helper signatures to use TooltipItemSorter | undefined instead of TooltipProps<number, string>['itemSorter']. Adjusted test cases and expected payloads to reflect string-valued sorter behavior.
Example components
www/src/components/GuideView/DomainAndTicks/MassBarChartCustomTicks.tsx, www/src/docs/exampleComponents/AreaChart/PercentAreaChart.tsx, www/src/docs/exampleComponents/BarChart/CandlestickExample.tsx, www/src/docs/exampleComponents/BarChart/PopulationPyramidExample.tsx, www/src/docs/exampleComponents/ComposedChart/BandedChart.tsx, www/src/docs/exampleComponents/ScatterChart/BubbleChart.tsx, www/src/docs/exampleComponents/Tooltip/CustomContentOfTooltip.tsx
Added TooltipValueType imports. Removed explicit generic type arguments from TooltipContentProps and Tooltip usage. Updated callback signatures (e.g., kgToYottagram, getPercent, renderTooltipContent) to accept TooltipValueType | undefined with type normalization via Number() or helper functions like toNumber.

Sequence Diagram(s)

sequenceDiagram
    participant Consumer as Custom Tooltip Consumer
    participant Tooltip as Tooltip Component
    participant DefaultContent as DefaultTooltipContent
    participant Sorter as Item Sorter
    participant Formatter as Formatter Function

    Consumer->>Tooltip: Provide payload data and itemSorter
    Tooltip->>DefaultContent: Pass TooltipContentProps with payload & itemSorter
    DefaultContent->>Sorter: Call itemSorter on each payload item
    Sorter-->>DefaultContent: Return sort key (dataKey | value | name | number | string)
    DefaultContent->>DefaultContent: Sort payload using lodashLikeSortBy
    loop For each sorted payload entry
        DefaultContent->>Formatter: Resolve entry.formatter or prop formatter
        Formatter-->>DefaultContent: Return formatted [value, name] or single value
        DefaultContent->>DefaultContent: Render tooltip item with finalValue/finalName
    end
    DefaultContent-->>Consumer: Render sorted and formatted tooltip items
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The changes introduce new types and logic patterns (TooltipItemSorter, lodashLikeSortBy, default generics) across multiple interconnected files (core components, tests, examples). While most individual changes are straightforward type updates or property renamings, the diverse scope—spanning component signatures, rendering logic, public API surface, and example code—requires careful verification of type consistency, behavioral correctness of the sorting/formatting refactor, and propagation of type changes through the example ecosystem.

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • ckifer
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% 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 'Fix tooltip payload type from any' accurately and concisely describes the main change: converting the tooltip payload type from 'any' to a specific type.
Description check ✅ Passed The PR description is complete with all required template sections: Description, Related Issue, Motivation and Context, Types of changes, and Checklist all properly filled out.
Linked Issues check ✅ Passed The PR successfully addresses the linked issue #6564 by changing the payload type from 'any' to a specific 'TooltipPayload' type, restoring type safety for custom tooltip components as required.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the tooltip payload typing issue: type definitions updated, examples modernized to use simplified generic signatures, tests updated for consistency.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/component/Tooltip.tsx (1)

55-67: Use @ts-expect-error comment instead of as any cast for React.createElement typing limitation.

This TypeScript limitation occurs when narrowing generic function types for React.createElement. The codebase establishes a pattern for this in src/component/Customized.tsx using @ts-expect-error comment, which is more explicit than an as any cast:

} else if (typeof component === 'function') {
  // `@ts-expect-error` TS cannot verify that C is FunctionComponent<P> here
  child = createElement(component, props as any);

Apply the same approach to renderContent for consistency.

🧹 Nitpick comments (2)
www/src/docs/exampleComponents/AreaChart/PercentAreaChart.tsx (1)

52-68: Improve type safety in toNumber helper.

The v variable is declared without a type or initial value, causing potential type ambiguity when passed to parseFloat(). Consider initializing it explicitly and using else if for clearer control flow.

♻️ Suggested improvement
 const toNumber = (value: TooltipValueType | undefined): number => {
   if (typeof value === 'number') {
     return value;
   }
-  let v;
-  if (typeof value === 'string') {
+  let v: string | undefined;
+  if (value == null) {
+    return 0;
+  } else if (typeof value === 'string') {
     v = value;
-  }
-  if (Array.isArray(value)) {
+  } else if (Array.isArray(value)) {
     [, v] = value;
   }
-  const parsed = parseFloat(v);
+  const parsed = parseFloat(v ?? '');
   if (!Number.isNaN(parsed)) {
     return parsed;
   }
   return 0;
 };
src/component/DefaultTooltipContent.tsx (1)

97-103: Verify the type assertion suppression is necessary.

The @ts-expect-error comment suppresses a type mismatch from sortBy. Consider whether the types could be improved to avoid suppression, or add a more descriptive comment explaining the specific type issue.

💡 Suggested improvement
 function lodashLikeSortBy<T>(array: ReadonlyArray<T>, itemSorter: TooltipItemSorter | undefined): ReadonlyArray<T> {
   if (itemSorter == null) {
     return array;
   }
-  // `@ts-expect-error` sortBy types somehow are returning a number type.
+  // `@ts-expect-error` es-toolkit/compat sortBy return type is incorrectly narrowed to number[]
+  // when the iteratee returns number | string | undefined. The actual runtime behavior is correct.
   return sortBy(array, itemSorter);
 }

@codecov
Copy link

codecov bot commented Jan 24, 2026

Codecov Report

❌ Patch coverage is 71.60494% with 23 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.26%. Comparing base (1f8b5be) to head (aa5cdb9).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
...s/exampleComponents/AreaChart/PercentAreaChart.tsx 22.72% 17 Missing ⚠️
src/component/DefaultTooltipContent.tsx 89.18% 4 Missing ⚠️
...ideView/DomainAndTicks/MassBarChartCustomTicks.tsx 33.33% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6925      +/-   ##
==========================================
- Coverage   94.29%   94.26%   -0.03%     
==========================================
  Files         571      571              
  Lines       56002    56023      +21     
  Branches     5222     5223       +1     
==========================================
+ Hits        52807    52810       +3     
- Misses       3186     3204      +18     
  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.

@github-actions
Copy link
Contributor

Staging Deployment Details

These deployments will remain available for 30 days.

To update snapshots: Comment /update-snapshots on this PR to automatically update the baseline screenshots.

@codecov
Copy link

codecov bot commented Jan 24, 2026

Bundle Report

Changes will increase total bundle size by 649 bytes (0.02%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
recharts/bundle-cjs 1.21MB 303 bytes (0.02%) ⬆️
recharts/bundle-umd 530.6kB 43 bytes (0.01%) ⬆️
recharts/bundle-es6 1.05MB 303 bytes (0.03%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: recharts/bundle-umd

Assets Changed:

Asset Name Size Change Total Size Change (%)
Recharts.js 43 bytes 530.6kB 0.01%
view changes for bundle: recharts/bundle-cjs

Assets Changed:

Asset Name Size Change Total Size Change (%)
component/Tooltip.js 49 bytes 9.42kB 0.52%
component/DefaultTooltipContent.js 254 bytes 7.32kB 3.6%
view changes for bundle: recharts/bundle-es6

Assets Changed:

Asset Name Size Change Total Size Change (%)
component/Tooltip.js 49 bytes 8.29kB 0.59%
component/DefaultTooltipContent.js 254 bytes 6.18kB 4.28%

Copy link
Member

@ckifer ckifer left a comment

Choose a reason for hiding this comment

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

Hard to tell if this is breaking or not. I suppose if it is then it's a correction

@ckifer
Copy link
Member

ckifer commented Jan 26, 2026

conflicts

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
www/src/docs/exampleComponents/AreaChart/PercentAreaChart.tsx (1)

1-71: Avoid implicit any in toNumber.

let v; becomes any under TS and violates the no-any rule. Please type it explicitly. As per coding guidelines, avoid implicit any.

🐛 Proposed fix
-  let v;
+  let v: number | string | undefined;
   if (typeof value === 'string') {
     v = value;
   }
   if (Array.isArray(value)) {
     [, v] = value;
   }
-  const parsed = parseFloat(v);
+  const parsed = typeof v === 'number' ? v : parseFloat(v ?? '');
🤖 Fix all issues with AI agents
In `@src/component/Tooltip.tsx`:
- Line 177: Change the labelFormatter prop signature in Tooltip.tsx from (label:
any, payload: TooltipPayload) => ReactNode to (label: ReactNode, payload:
TooltipPayload) => ReactNode so it matches DefaultTooltipContent.tsx and the
actual prop type; update the import/usage to reference ReactNode (import from
'react' or use React.ReactNode) and adjust any internal calls or tests that pass
a typed label to the labelFormatter to satisfy the new ReactNode parameter type
(identify the prop name labelFormatter and the Tooltip component type definition
to make the change).

In `@test/component/Tooltip/itemSorter.spec.tsx`:
- Line 1: The test file is missing an explicit import of beforeEach from vitest;
update the top import statement (the line that currently imports describe,
expect, it, vi) to also import beforeEach so all usages of beforeEach (e.g., the
beforeEach blocks in this file) are explicitly imported from vitest and avoid
relying on globals.

In `@www/src/docs/exampleComponents/BarChart/PopulationPyramidExample.tsx`:
- Around line 59-61: formatPercent currently calls Number(val) and can produce
NaN when val is an array (TooltipValueType may be ReadonlyArray<number|string>);
update formatPercent to guard for arrays by checking Array.isArray(val) and
extracting a single numeric candidate (e.g., first element) before conversion,
then coerce that candidate to Number (handling string numbers) and fall back to
0 if conversion fails, finally returning `${Math.abs(numberValue).toFixed(1)}%`;
reference the formatPercent function and TooltipValueType/RenderableText when
making the change.
🧹 Nitpick comments (2)
www/src/docs/exampleComponents/ScatterChart/BubbleChart.tsx (1)

79-103: Add an explicit return type for renderTooltip.

This helper isn’t a React component; make the return type explicit to satisfy the TS typing rule. As per coding guidelines, please avoid inferred return types here.

♻️ Proposed change
-const renderTooltip = (props: TooltipContentProps) => {
+const renderTooltip = (props: TooltipContentProps): ReactNode => {
www/src/docs/exampleComponents/AreaChart/PercentAreaChart.tsx (1)

77-80: Add an explicit return type for renderTooltipContent.

This helper is not a React component; give it an explicit return type. As per coding guidelines, avoid inferred return types for non-component functions.

♻️ Proposed change
-const renderTooltipContent = (o: TooltipContentProps) => {
+const renderTooltipContent = (o: TooltipContentProps): JSX.Element => {

* The formatter function of label in tooltip.
*/
labelFormatter?: (label: any, payload: Payload<TValue, TName>[]) => ReactNode;
labelFormatter?: (label: any, payload: TooltipPayload) => ReactNode;
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's find and examine the Tooltip.tsx file
fd -t f "Tooltip.tsx" src/

# Then read the relevant section
cat -n src/component/Tooltip.tsx | sed -n '170,185p'

Repository: recharts/recharts

Length of output: 754


🏁 Script executed:

# Search for how labelFormatter is actually used in the codebase
rg "labelFormatter" -A 3 -B 3 src/

Repository: recharts/recharts

Length of output: 2158


🏁 Script executed:

# Check what types are typically passed to labelFormatter
rg "labelFormatter\s*=" -A 5 src/ | head -50

Repository: recharts/recharts

Length of output: 43


🏁 Script executed:

# Search for labelFormatter usage in examples and tests
rg "labelFormatter\s*:\s*\(" -B 2 -A 5 src/ | head -80

Repository: recharts/recharts

Length of output: 43


🏁 Script executed:

# Check if there are any test files showing labelFormatter usage
fd -t f -e "test.ts" -e "spec.ts" -e "test.tsx" src/ | xargs rg "labelFormatter" -A 3 | head -60

Repository: recharts/recharts

Length of output: 4213


🏁 Script executed:

# Look at the TooltipPayload type to understand context
rg "type TooltipPayload" -A 10 src/

Repository: recharts/recharts

Length of output: 3351


🏁 Script executed:

# Check what type of label is passed to labelFormatter in DefaultTooltipContent
cat -n src/component/DefaultTooltipContent.tsx | sed -n '1,100p' | grep -A 20 "labelFormatter"

Repository: recharts/recharts

Length of output: 771


🏁 Script executed:

# Check the actual implementation where labelFormatter is called
cat -n src/component/DefaultTooltipContent.tsx | sed -n '80,120p'

Repository: recharts/recharts

Length of output: 1507


🏁 Script executed:

# Look for how label is defined/passed in DefaultTooltipContent
rg "label\s*[:=]" src/component/DefaultTooltipContent.tsx | head -20

Repository: recharts/recharts

Length of output: 213


🏁 Script executed:

# Check how Tooltip passes labelFormatter to DefaultTooltipContent
rg "DefaultTooltipContent" src/component/Tooltip.tsx -B 5 -A 5

Repository: recharts/recharts

Length of output: 1791


🏁 Script executed:

# Check if there's a reason for the type difference between the two files
git log -p --follow -S "labelFormatter" -- src/component/Tooltip.tsx src/component/DefaultTooltipContent.tsx 2>/dev/null | head -100

Repository: recharts/recharts

Length of output: 43


Update labelFormatter parameter type from any to ReactNode for consistency.

The label parameter currently uses any, which violates the TypeScript guidelines. Additionally, DefaultTooltipContent.tsx already types this as ReactNode, and the label value passed to labelFormatter comes directly from the component's label: ReactNode prop. Align Tooltip.tsx with the implementation.

Proposed fix
-  labelFormatter?: (label: any, payload: TooltipPayload) => ReactNode;
+  labelFormatter?: (label: ReactNode, payload: TooltipPayload) => ReactNode;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
labelFormatter?: (label: any, payload: TooltipPayload) => ReactNode;
labelFormatter?: (label: ReactNode, payload: TooltipPayload) => ReactNode;
🤖 Prompt for AI Agents
In `@src/component/Tooltip.tsx` at line 177, Change the labelFormatter prop
signature in Tooltip.tsx from (label: any, payload: TooltipPayload) => ReactNode
to (label: ReactNode, payload: TooltipPayload) => ReactNode so it matches
DefaultTooltipContent.tsx and the actual prop type; update the import/usage to
reference ReactNode (import from 'react' or use React.ReactNode) and adjust any
internal calls or tests that pass a typed label to the labelFormatter to satisfy
the new ReactNode parameter type (identify the prop name labelFormatter and the
Tooltip component type definition to make the change).

@@ -1,4 +1,4 @@
import { describe, it, expect, vi } from 'vitest';
import { describe, expect, it, vi } from 'vitest';
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

Missing beforeEach import.

The beforeEach function is used throughout this file (lines 42, 911, 964, 1280, 1946, 2337) but is not included in the vitest imports. While vitest may provide it globally, explicit imports are preferred for clarity and to avoid potential issues.

🔧 Suggested fix
-import { describe, expect, it, vi } from 'vitest';
+import { beforeEach, describe, expect, it, vi } from 'vitest';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { describe, expect, it, vi } from 'vitest';
import { beforeEach, describe, expect, it, vi } from 'vitest';
🤖 Prompt for AI Agents
In `@test/component/Tooltip/itemSorter.spec.tsx` at line 1, The test file is
missing an explicit import of beforeEach from vitest; update the top import
statement (the line that currently imports describe, expect, it, vi) to also
import beforeEach so all usages of beforeEach (e.g., the beforeEach blocks in
this file) are explicitly imported from vitest and avoid relying on globals.

Comment on lines +59 to 61
function formatPercent(val: RenderableText | TooltipValueType): string {
return `${Math.abs(Number(val)).toFixed(1)}%`;
}
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

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the file and the formatPercent function
cat -n www/src/docs/exampleComponents/BarChart/PopulationPyramidExample.tsx | head -80 | tail -30

Repository: recharts/recharts

Length of output: 1133


🏁 Script executed:

# Search for TooltipValueType definition
rg "type TooltipValueType|interface TooltipValueType" -A 5

Repository: recharts/recharts

Length of output: 43


🏁 Script executed:

# Search for RenderableText definition
rg "type RenderableText|interface RenderableText" -A 5

Repository: recharts/recharts

Length of output: 446


🏁 Script executed:

# Check imports in the file to see where these types come from
head -30 www/src/docs/exampleComponents/BarChart/PopulationPyramidExample.tsx

Repository: recharts/recharts

Length of output: 672


🏁 Script executed:

# Look for all usages of formatPercent in the file
rg "formatPercent" www/src/docs/exampleComponents/BarChart/PopulationPyramidExample.tsx -B 2 -A 2

Repository: recharts/recharts

Length of output: 759


🏁 Script executed:

# Search for TooltipValueType definition in recharts source
rg "type TooltipValueType|export.*TooltipValueType" -A 5

Repository: recharts/recharts

Length of output: 43


🏁 Script executed:

# Also check the types directory
fd "TooltipValueType|tooltip" -t f src/

Repository: recharts/recharts

Length of output: 194


🏁 Script executed:

# Look for tooltip-related type definitions
rg "TooltipValueType" src/ -A 3 | head -50

Repository: recharts/recharts

Length of output: 350


🏁 Script executed:

# Find the ValueType definition in DefaultTooltipContent
rg "type ValueType|export.*ValueType" src/component/DefaultTooltipContent.tsx -A 5

Repository: recharts/recharts

Length of output: 1083


🏁 Script executed:

# Also check what's exported from that file
cat src/component/DefaultTooltipContent.tsx | head -100

Repository: recharts/recharts

Length of output: 3105


🏁 Script executed:

# Let's verify what Number([1,2]) does
python3 << 'EOF'
# JavaScript behavior
results = []
results.append(f"Number([1,2]) behavior:")
# In JavaScript: Number([1,2]) = NaN (single element arrays work, multiple don't)
# Number([1]) = 1
# Number([]) = 0
# Number(['1']) = 1
# Number(['1', '2']) = NaN

# Let's verify this with Node if available
import subprocess
try:
    result = subprocess.run(['node', '-e', 'console.log(Number([1,2]), Number([1]), Number([]), Number("1,2"))'], 
                          capture_output=True, text=True, timeout=5)
    results.append(f"Node.js output: {result.stdout.strip()}")
except Exception as e:
    results.append(f"Could not test: {e}")

for r in results:
    print(r)
EOF

Repository: recharts/recharts

Length of output: 147


🏁 Script executed:

# Check how the Tooltip actually passes values to the formatter
rg "formatter" src/component/Tooltip.tsx -B 2 -A 2 | head -50

Repository: recharts/recharts

Length of output: 408


🏁 Script executed:

# Look for context on how formatters receive their values
rg "formatter.*value" src/component/DefaultTooltipContent.tsx -B 2 -A 2 | head -60

Repository: recharts/recharts

Length of output: 43


🏁 Script executed:

# Check if there are other examples in the codebase handling array values in formatters
rg "Array.isArray.*val|is.*Array.*formatter" src/ --type tsx --type ts -B 2 -A 2 | head -40

Repository: recharts/recharts

Length of output: 88


🏁 Script executed:

# Look for tooltip examples that might show array handling
fd ".*ooltip.*example" www/src/docs -i

Repository: recharts/recharts

Length of output: 43


🏁 Script executed:

# Check what real data gets passed to formatPercent by looking at tooltip usage context
rg "Tooltip" www/src/docs/exampleComponents/BarChart/PopulationPyramidExample.tsx -B 5 -A 5

Repository: recharts/recharts

Length of output: 1012


Handle array-valued TooltipValueType to prevent NaN in formatting.

TooltipValueType includes ReadonlyArray<number | string>, but the function doesn't guard against arrays. When Number() is called on multi-element arrays like [1,2], it returns NaN. Add a guard to extract a numeric value from array inputs.

♻️ Proposed change
 function formatPercent(val: RenderableText | TooltipValueType): string {
-  return `${Math.abs(Number(val)).toFixed(1)}%`;
+  const value = Array.isArray(val) ? val[1] ?? val[0] : val;
+  return `${Math.abs(Number(value)).toFixed(1)}%`;
 }
🤖 Prompt for AI Agents
In `@www/src/docs/exampleComponents/BarChart/PopulationPyramidExample.tsx` around
lines 59 - 61, formatPercent currently calls Number(val) and can produce NaN
when val is an array (TooltipValueType may be ReadonlyArray<number|string>);
update formatPercent to guard for arrays by checking Array.isArray(val) and
extracting a single numeric candidate (e.g., first element) before conversion,
then coerce that candidate to Number (handling string numbers) and fall back to
0 if conversion fails, finally returning `${Math.abs(numberValue).toFixed(1)}%`;
reference the formatPercent function and TooltipValueType/RenderableText when
making the change.

@github-actions
Copy link
Contributor

Staging Deployment Details

These deployments will remain available for 30 days.

To update snapshots: Comment /update-snapshots on this PR to automatically update the baseline screenshots.

@ckifer ckifer merged commit 265bb5b into main Jan 27, 2026
50 of 53 checks passed
@ckifer ckifer deleted the tooltip-payload branch January 27, 2026 17:58
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.

v3 custom tooltip payload type

2 participants