Skip to content

fix(DefaultLegendContent): use entry.value for aria-label when formatter returns React element#7109

Merged
PavelVanecek merged 1 commit intorecharts:mainfrom
mixelburg:fix/legend-aria-label-formatter
Mar 8, 2026
Merged

fix(DefaultLegendContent): use entry.value for aria-label when formatter returns React element#7109
PavelVanecek merged 1 commit intorecharts:mainfrom
mixelburg:fix/legend-aria-label-formatter

Conversation

@mixelburg
Copy link
Copy Markdown
Contributor

@mixelburg mixelburg commented Mar 6, 2026

Problem

When a Legend formatter returns a React element (JSX), the aria-label on each legend icon <svg> ends up as "[object Object] legend icon" because the formatter's return value is coerced to a string via a template literal.

Repro:

<LineChart width={500} height={300} data={data}>
  <Legend formatter={value => <strong>{value}</strong>} />
  <Line dataKey="value" name="UV" />
</LineChart>

Produces: aria-label="[object Object] legend icon"
Expected: aria-label="UV legend icon"

Fixes #7105.

Root Cause

In DefaultLegendContent.tsx, the icon surface element uses finalValue (the formatter's return value) for the aria-label:

const finalValue = formatter ? formatter(value, entry, i) : value;
// ...
<Surface aria-label={`${finalValue} legend icon`} ...>

finalValue may be a React element, which stringifies to [object Object].

Fix

Use entry.value (the raw string data key/name) for the aria-label instead of finalValue. The formatter output is the visual label and may be arbitrary JSX; the accessible name should always reflect the underlying series name.

-  aria-label={`${finalValue} legend icon`}
+  aria-label={`${entry.value} legend icon`}

Test

A new test case in test/component/Legend.spec.tsx verifies that aria-label uses the raw entry value even when the formatter returns JSX.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed legend accessibility by updating aria-labels to consistently display raw data values instead of potentially formatted display text. This ensures screen reader users receive accurate and predictable information when interacting with chart legends.

…ter returns React element

When a Legend formatter returns a React element (JSX), the aria-label on
each legend icon SVG was set to '[object Object] legend icon' because
the formatter's return value was stringified via a template literal.

The aria-label should always reflect the human-readable name of the series,
not the visual representation. Use entry.value (the raw string passed into
formatter) for the aria-label instead.

Fixes recharts#7105
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 6, 2026

Walkthrough

The PR modifies the aria-label attribute in DefaultLegendContent to use the raw entry.value instead of the formatted finalValue. This ensures accessibility labels reflect the original data value regardless of formatter output. A test case verifies this behavior with React element formatters.

Changes

Cohort / File(s) Summary
Legend Accessibility Fix
src/component/DefaultLegendContent.tsx
Changed aria-label for legend item SVG icon from using finalValue (formatter output) to entry.value (raw data value) to ensure accessibility labels reflect the original data regardless of formatter behavior.
Legend Test Coverage
test/component/Legend.spec.tsx
Added test case verifying that Legend aria-label uses raw entry value even when the Legend formatter returns a React element (e.g., <strong> tag).

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • ckifer
  • PavelVanecek
🚥 Pre-merge checks | ✅ 2 | ❌ 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 (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main change: fixing aria-label to use entry.value instead of the formatter result in DefaultLegendContent.
Description check ✅ Passed The pull request description is comprehensive and follows the template structure with all required sections completed.

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

✨ Finishing Touches
🧪 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
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/component/DefaultLegendContent.tsx`:
- Line 241: Guard the aria-label on the Legend item to avoid stringifying
undefined: in DefaultLegendContent where the JSX sets
aria-label={`${entry.value} legend icon`}, change it to conditionally use a safe
fallback (e.g. entry.value ?? '' or a more descriptive fallback like
entry.payload?.name ?? 'legend') so you never render "undefined legend icon";
update the aria-label expression (referencing entry.value and
entry.payload/name) to build a meaningful label only when value exists and
otherwise produce a safe default.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fbe18990-92e1-4890-b4f2-d122b316d10d

📥 Commits

Reviewing files that changed from the base of the PR and between c04a790 and 46096d3.

📒 Files selected for processing (2)
  • src/component/DefaultLegendContent.tsx
  • test/component/Legend.spec.tsx

viewBox={viewBox}
style={svgStyle}
aria-label={`${finalValue} legend icon`}
aria-label={`${entry.value} legend icon`}
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 | 🟡 Minor

Guard the aria-label when entry.value is missing.

Line 241 still stringifies LegendPayload.value, so unnamed legend items end up with aria-label="undefined legend icon". LegendPayload.value is explicitly optional here, and the payload builders shown in src/util/ChartUtils.ts can produce undefined, so this remains a real accessibility bug.

Suggested fix
-          aria-label={`${entry.value} legend icon`}
+          aria-label={entry.value == null ? undefined : `${entry.value} legend icon`}

Based on learnings: Ensure accessibility is important in Recharts components and implementation.

📝 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
aria-label={`${entry.value} legend icon`}
aria-label={entry.value == null ? undefined : `${entry.value} legend icon`}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/component/DefaultLegendContent.tsx` at line 241, Guard the aria-label on
the Legend item to avoid stringifying undefined: in DefaultLegendContent where
the JSX sets aria-label={`${entry.value} legend icon`}, change it to
conditionally use a safe fallback (e.g. entry.value ?? '' or a more descriptive
fallback like entry.payload?.name ?? 'legend') so you never render "undefined
legend icon"; update the aria-label expression (referencing entry.value and
entry.payload/name) to build a meaningful label only when value exists and
otherwise produce a safe default.

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 6, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.62%. Comparing base (c04a790) to head (46096d3).
⚠️ Report is 8 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7109   +/-   ##
=======================================
  Coverage   89.62%   89.62%           
=======================================
  Files         534      534           
  Lines       40193    40193           
  Branches     5465     5465           
=======================================
  Hits        36024    36024           
  Misses       4161     4161           
  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.

@PavelVanecek PavelVanecek merged commit da03436 into recharts:main Mar 8, 2026
41 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.

'DefaultLegendContent' uses formatter return value for aria-label, producing [object Object] when formatter returns a React element

2 participants