Skip to content

fixes an issue where XAxis and YAxis padding were ignored by the clipping mask when allowDataOverflow={true} was used alongside a restricted domain#7232

Merged
PavelVanecek merged 2 commits into
recharts:mainfrom
emiedonmokumo:main
Apr 14, 2026

Conversation

@emiedonmokumo

@emiedonmokumo emiedonmokumo commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Description

This PR fixes an issue where XAxis and YAxis padding were ignored by the clipping mask when allowDataOverflow={true} was used alongside a restricted domain.

Previously, the GraphicalItemClipPath component calculated its clipping rectangle using the broad plotArea dimensions. This caused data to "bleed" into the padded areas because the mask wasn't aware of the specific padding applied to the axes.

I updated GraphicalItemClipPath to use the actual computed ranges for the axes (selectXAxisRange and selectYAxisRange). This ensures the clipping rectangle strictly matches the padded boundaries, cutting off overflowing data precisely where the axis ends.

Related Issue

Fixes #6947

How Has This Been Tested?

I tested this locally using Vitest.

  • Created a reproduction test case with a BarChart, domain strictness, allowDataOverflow={true}, and padding={{ right: 50 }}. I verified that the rendered <clipPath> now correctly reduces its width/height to respect the padding (e.g., width goes from 330px to 280px).
  • Ran the Recharts unit test suite: vitest run test/cartesian/XAxis/XAxis.padding.spec.tsx and test/cartesian/Bar.truncateByDomain.spec.tsx to verify that existing truncation and padding behaviors are unaffected and no regressions were introduced.

Screenshots (if appropriate):

(Note: You can drag and drop a before/after screenshot of the chart here if you'd like to show the visual difference)

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

  • Bug Fixes
    • Improved clipping of chart elements at plot-area boundaries by using actual axis ranges, reducing visual overflow and ensuring correct clipping when data overflow and padding are applied.
  • Tests
    • Added tests that validate clipping behavior with padding in both allow-data-overflow enabled and disabled scenarios.

@coderabbitai

coderabbitai Bot commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Use Redux axis-range selectors in GraphicalItemClipPath.tsx to compute SVG clip <rect> geometry from actual axis ranges when available; otherwise fall back to previous centered/double-size behavior. Added a test verifying XAxis padding + allowDataOverflow clipping behavior.

Changes

Cohort / File(s) Summary
Clip Path Geometry
src/cartesian/GraphicalItemClipPath.tsx
Added selectXAxisRange / selectYAxisRange lookups and replaced conditional rect props with derived clipX, clipY, clipWidth, clipHeight that use axis ranges (Math.min / absolute spans) when present; preserves prior fallback behavior.
Tests (XAxis padding/clip)
test/cartesian/XAxis/XAxis.padding_clip.spec.tsx
New Vitest/RTL spec validating XAxis clipping with padding when allowDataOverflow is true vs false; asserts generated SVG <clipPath><rect> attributes match expected values.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Ts strict #6750 — Related changes touching axis-range selectors and selector typings/shape that overlap the selector surface used here.

Suggested reviewers

  • ckifer
  • PavelVanecek
🚥 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
Description check ✅ Passed Description covers the issue, solution, testing, and correctly identifies it as a bug fix, but the 'I have added tests to cover my changes' checkbox remains unchecked despite the new test file being added.
Linked Issues check ✅ Passed Code changes directly address issue #6947 by modifying GraphicalItemClipPath to use Redux selectors for axis ranges and updating clip geometry calculations to respect padding boundaries.
Out of Scope Changes check ✅ Passed All changes are in scope: GraphicalItemClipPath fix for clipping behavior and XAxis.padding_clip.spec.tsx test file directly address the linked issue.
Title check ✅ Passed The title accurately describes the main fix: addressing ignored XAxis/YAxis padding in the clipping mask when allowDataOverflow={true} with a restricted domain.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@emiedonmokumo

Copy link
Copy Markdown
Contributor Author

@ckifer can you please review?

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/cartesian/GraphicalItemClipPath.tsx (1)

35-51: Please add/keep a regression test that asserts clipPath rect geometry from axis ranges.

This path is the core fix, so a focused assertion on <rect x/y/width/height> with restricted domain + allowDataOverflow={true} + axis padding will protect against regressions.

As per coding guidelines, "src/**/*.{ts,tsx}: Aim for 100% unit test code coverage when writing new code".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cartesian/GraphicalItemClipPath.tsx` around lines 35 - 51, Add or retain
a regression unit test that mounts GraphicalItemClipPath (or the parent that
renders it) with a restricted domain, allowDataOverflow={true}, and axis padding
enabled, then assert the rendered <rect> has x/y/width/height matching
calculations derived from selectXAxisRange/selectYAxisRange (i.e., Math.min
range start/end for x/y and Math.abs difference for width/height) for the
clipPath with id `clipPath-${clipPathId}`; target the props and internal flags
needClipX/needClipY and plotArea values used by GraphicalItemClipPath so the
test fails if the clip geometry deviates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/cartesian/GraphicalItemClipPath.tsx`:
- Around line 35-51: Add or retain a regression unit test that mounts
GraphicalItemClipPath (or the parent that renders it) with a restricted domain,
allowDataOverflow={true}, and axis padding enabled, then assert the rendered
<rect> has x/y/width/height matching calculations derived from
selectXAxisRange/selectYAxisRange (i.e., Math.min range start/end for x/y and
Math.abs difference for width/height) for the clipPath with id
`clipPath-${clipPathId}`; target the props and internal flags
needClipX/needClipY and plotArea values used by GraphicalItemClipPath so the
test fails if the clip geometry deviates.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a2dafde8-0d96-473f-8348-2da4549612e6

📥 Commits

Reviewing files that changed from the base of the PR and between a75d6fd and b0f3db1.

📒 Files selected for processing (1)
  • src/cartesian/GraphicalItemClipPath.tsx

@PavelVanecek

Copy link
Copy Markdown
Collaborator

Commit the reproduction too please, we will need a test.

@codecov

codecov Bot commented Apr 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.07%. Comparing base (a75d6fd) to head (80cfe7e).
⚠️ Report is 7 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7232   +/-   ##
=======================================
  Coverage   89.07%   89.07%           
=======================================
  Files         539      539           
  Lines       41014    41015    +1     
  Branches     5554     5556    +2     
=======================================
+ Hits        36532    36533    +1     
  Misses       4474     4474           
  Partials        8        8           

☔ 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.

@codecov

codecov Bot commented Apr 10, 2026

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 4.84kB (0.09%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
recharts/bundle-cjs 1.3MB 533 bytes (0.04%) ⬆️
recharts/bundle-es6 1.13MB 505 bytes (0.04%) ⬆️
recharts/bundle-umd 551.33kB 3.33kB (0.61%) ⬆️
recharts/bundle-treeshaking-cartesian 644.51kB 469 bytes (0.07%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: recharts/bundle-treeshaking-cartesian

Assets Changed:

Asset Name Size Change Total Size Change (%)
bundle.js 469 bytes 644.51kB 0.07%
view changes for bundle: recharts/bundle-es6

Assets Changed:

Asset Name Size Change Total Size Change (%)
cartesian/GraphicalItemClipPath.js 505 bytes 2.19kB 29.88% ⚠️
view changes for bundle: recharts/bundle-umd

Assets Changed:

Asset Name Size Change Total Size Change (%)
Recharts.js 3.33kB 551.33kB 0.61%
view changes for bundle: recharts/bundle-cjs

Assets Changed:

Asset Name Size Change Total Size Change (%)
cartesian/GraphicalItemClipPath.js 533 bytes 3.08kB 20.9% ⚠️

… the clipping rectangle matches the padded range when overflow is true and default clipping behavior remains unchanged when overflow is false.
@emiedonmokumo

Copy link
Copy Markdown
Contributor Author

@PavelVanecek I have created a test file.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/cartesian/XAxis/XAxis.padding_clip.spec.tsx (1)

6-58: Prefer createSelectorTestCase here to track selector-call churn.

This spec is a good candidate for createSelectorTestCase so you can assert both behavior and selector call counts, which helps prevent rerender regressions in cartesian selectors.

As per coding guidelines, "Prefer to use the createSelectorTestCase helper function when writing or modifying tests" and "Verify the number of selector calls using the spy object from createSelectorTestCase to spot unnecessary re-renders and improve performance."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/cartesian/XAxis/XAxis.padding_clip.spec.tsx` around lines 6 - 58, The
test for XAxis padding should use the createSelectorTestCase helper to assert
both behavior and selector call counts: replace the two standalone it() cases
with a createSelectorTestCase that renders the same BarChart + XAxis scenarios
(allowDataOverflow true/false), import and use createSelectorTestCase and its
selectorSpy to verify the expected DOM clipPath results while also asserting the
relevant cartesian selectors were called the expected number of times; locate
the test around the current XAxis padding specs and update the render logic for
BarChart/XAxis and assertions to use the helper and selectorSpy instead of plain
render + DOM-only expectations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/cartesian/XAxis/XAxis.padding_clip.spec.tsx`:
- Around line 8-21: After each render call in XAxis.padding_clip.spec.tsx (the
render invoking <BarChart ...> and any subsequent renders in the same test),
call vi.runOnlyPendingTimers() to flush pending timers and RAF callbacks before
performing DOM assertions; update the test so that immediately after the
render(...) that mounts the BarChart (the one that includes <XAxis dataKey="x"
... padding={{ left: 10, right: 50 }} /> and <Bar dataKey="y" ... />) you invoke
vi.runOnlyPendingTimers() to ensure clipPath rect attributes are stable before
querying them.

---

Nitpick comments:
In `@test/cartesian/XAxis/XAxis.padding_clip.spec.tsx`:
- Around line 6-58: The test for XAxis padding should use the
createSelectorTestCase helper to assert both behavior and selector call counts:
replace the two standalone it() cases with a createSelectorTestCase that renders
the same BarChart + XAxis scenarios (allowDataOverflow true/false), import and
use createSelectorTestCase and its selectorSpy to verify the expected DOM
clipPath results while also asserting the relevant cartesian selectors were
called the expected number of times; locate the test around the current XAxis
padding specs and update the render logic for BarChart/XAxis and assertions to
use the helper and selectorSpy instead of plain render + DOM-only expectations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5ac7c75d-2bf9-4987-a091-88aa9d0add12

📥 Commits

Reviewing files that changed from the base of the PR and between b0f3db1 and 80cfe7e.

📒 Files selected for processing (1)
  • test/cartesian/XAxis/XAxis.padding_clip.spec.tsx

Comment on lines +8 to +21
const { container } = render(
<BarChart
width={400}
height={400}
data={[
{ x: 0, y: 10 },
{ x: 100, y: 30 },
]}
>
<XAxis dataKey="x" type="number" domain={[0, 100]} allowDataOverflow padding={{ left: 10, right: 50 }} />
<YAxis />
<Bar dataKey="y" isAnimationActive={false} />
</BarChart>,
);

Copy link
Copy Markdown
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:

cat -n test/cartesian/XAxis/XAxis.padding_clip.spec.tsx

Repository: recharts/recharts

Length of output: 2322


🏁 Script executed:

rg -A 10 "BarChart" test/ -t tsx -t ts | grep -A 10 "render(" | head -50

Repository: recharts/recharts

Length of output: 88


🏁 Script executed:

rg -A 10 "BarChart" test/cartesian/ | grep -B 5 -A 10 "vi.runOnlyPendingTimers\|render(" | head -80

Repository: recharts/recharts

Length of output: 5526


🏁 Script executed:

rg "render\(" test/cartesian/ -A 3 | grep -B 3 "vi.runOnlyPendingTimers" | head -60

Repository: recharts/recharts

Length of output: 43


🏁 Script executed:

rg "vi.runOnlyPendingTimers" test/ -B 5 | head -100

Repository: recharts/recharts

Length of output: 6393


🏁 Script executed:

rg "isAnimationActive={false}" test/cartesian/ -A 10 | grep -B 5 -A 5 "render\(" | head -80

Repository: recharts/recharts

Length of output: 211


🏁 Script executed:

rg "isAnimationActive=\{false\}" test/cartesian/ -A 10 -B 3 | head -100

Repository: recharts/recharts

Length of output: 7746


🏁 Script executed:

cat test/cartesian/XAxis/XAxis.tick.spec.tsx | head -100

Repository: recharts/recharts

Length of output: 3153


🏁 Script executed:

rg "render\(" test/cartesian/XAxis/ -A 20 | rg -c "vi.runOnlyPendingTimers"

Repository: recharts/recharts

Length of output: 43


🏁 Script executed:

cat test/cartesian/XAxis/XAxis.padding.spec.tsx | head -80

Repository: recharts/recharts

Length of output: 2851


🏁 Script executed:

find test/cartesian -name "*.spec.tsx" -exec grep -l "render" {} \; | while read file; do echo "=== $file ==="; grep -A 1 "const { container } = render" "$file" | head -4; done | head -100

Repository: recharts/recharts

Length of output: 4378


🏁 Script executed:

rg "render\(" test/cartesian/ -A 5 | rg -B 5 "querySelectorAll\|querySelector" | head -100

Repository: recharts/recharts

Length of output: 43


🏁 Script executed:

grep -n "querySelectorAll\|querySelector" test/cartesian/XAxis/XAxis.padding_clip.spec.tsx

Repository: recharts/recharts

Length of output: 219


🏁 Script executed:

cat test/cartesian/XAxis/XAxis.padding_clip.spec.tsx

Repository: recharts/recharts

Length of output: 1916


Add vi.runOnlyPendingTimers() after each render to ensure timers and RAF callbacks are flushed before DOM assertions.

The test renders BarChart without calling vi.runOnlyPendingTimers() after render on lines 8 and 32. Per coding guidelines, tests must advance pending timers after renders when not using createSelectorTestCase. Even with isAnimationActive={false}, Redux batching and requestAnimationFrame callbacks may cause DOM state changes that need to be flushed before querying clipPath rect attributes.

Suggested patch
-import { describe, expect, it } from 'vitest';
+import { describe, expect, it, vi } from 'vitest';
@@
     );
+    vi.runOnlyPendingTimers();
@@
     );
+    vi.runOnlyPendingTimers();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/cartesian/XAxis/XAxis.padding_clip.spec.tsx` around lines 8 - 21, After
each render call in XAxis.padding_clip.spec.tsx (the render invoking <BarChart
...> and any subsequent renders in the same test), call
vi.runOnlyPendingTimers() to flush pending timers and RAF callbacks before
performing DOM assertions; update the test so that immediately after the
render(...) that mounts the BarChart (the one that includes <XAxis dataKey="x"
... padding={{ left: 10, right: 50 }} /> and <Bar dataKey="y" ... />) you invoke
vi.runOnlyPendingTimers() to ensure clipPath rect attributes are stable before
querying them.

@emiedonmokumo

Copy link
Copy Markdown
Contributor Author

Hi @PavelVanecek 👋

@PavelVanecek

Copy link
Copy Markdown
Collaborator

Before

image

After

image

@PavelVanecek PavelVanecek changed the title fix(cartesian): Identifies this as a bug fix in the cartesian components. fixes an issue where XAxis and YAxis padding were ignored by the clipping mask when allowDataOverflow={true} was used alongside a restricted domain Apr 14, 2026
@PavelVanecek
PavelVanecek merged commit d99d8dc into recharts:main Apr 14, 2026
51 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Apr 18, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Jun 25, 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.

XAxis padding is not reflected when domain is limited and allowDataOverflow equals true

2 participants