Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use Recharts to build a React bar graph when you want declarative components, native SVG output, and a straightforward path to responsive and accessible charts. Install the package, compose BarChart, Bar, axes, grid, and tooltip components, then place the chart in a parent with a real height. The complete example below covers a basic chart, grouped and stacked data, responsive sizing, accessibility, labels, animation, and production troubleshooting.

Choose a React bar-chart approach

For most React applications, Recharts is the practical starting point. Its package describes it as “a Redefined chart library built with React and D3.” The API is declarative: your JSX describes the chart and its data rather than requiring you to manipulate an imperative drawing surface. Recharts renders charts as SVG, so browser sizing, CSS, keyboard behavior, and SVG-compatible labels fit naturally into a React component model.

A bar graph is appropriate when the reader must compare discrete categories: revenue by quarter, tickets by team, or downloads by platform. Use side-by-side bars when comparing separate series at each category. Use stacked bars when the meaningful question is how parts combine into a total. If the data is continuous over time and the emphasis is a trend, a line chart may communicate better.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install Recharts

From your React project directory, install the package with npm:

npm install recharts

Then restart the development server if it was already running. The component names used in the example are exported by Recharts: BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, and ResponsiveContainer.

Build a minimal bar graph

Create a component such as SalesBarChart.jsx. Each object in data represents one category. dataKey tells Recharts which property supplies a category label or numeric value.

import {
  BarChart,
  Bar,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  ResponsiveContainer,
} from 'recharts';

const data = [
  { name: 'A', value: 12 },
  { name: 'B', value: 19 },
  { name: 'C', value: 7 },
];

export default function Example() {
  return (
    <div style={{ width: '100%', height: 320 }}>
      <ResponsiveContainer width="100%" height="100%">
        <BarChart data={data} margin={{ top: 16, right: 16, bottom: 16, left: 8 }}>
          <CartesianGrid strokeDasharray="3 3" />
          <XAxis dataKey="name" />
          <YAxis />
          <Tooltip />
          <Bar dataKey="value" fill="#2563eb" name="Value" />
        </BarChart>
      </ResponsiveContainer>
    </div>
  );
}

The outer div is important. A percentage width can resolve against the parent, but a chart cannot draw usefully when its parent has no height. The example gives the parent a 320-pixel height and lets ResponsiveContainer follow its width.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make the chart responsive

ResponsiveContainer watches its parent with the browser’s ResizeObserver API. Set width="100%" and either a percentage height with a sized parent or a fixed height. In a card layout, use CSS instead of an inline style:

.chart-card {
  width: 100%;
  height: 22rem;
}

@media (max-width: 600px) {
  .chart-card { height: 18rem; }
}

Wrap the component in <div className="chart-card"> and use height="100%" on the container. If you support browsers without ResizeObserver, provide a compatible polyfill or use a fixed chart size. Avoid putting the chart in a hidden tab at initial render; a parent measured at zero can produce an empty chart until it is resized.

Recent Recharts versions also support a responsive prop on BarChart for CSS-driven sizing. Use one sizing strategy consistently. ResponsiveContainer remains useful when the chart should explicitly track a parent element.

Grouped bars for side-by-side comparisons

Give each series its own Bar with the same category axis. Recharts places them side by side by default:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const quarterly = [
  { quarter: 'Q1', product: 42, services: 28 },
  { quarter: 'Q2', product: 51, services: 33 },
  { quarter: 'Q3', product: 47, services: 39 },
];

function GroupedChart() {
  return (
    <div style={{ width: '100%', height: 320 }}>
      <ResponsiveContainer width="100%" height="100%">
        <BarChart data={quarterly}>
          <CartesianGrid strokeDasharray="3 3" />
          <XAxis dataKey="quarter" />
          <YAxis />
          <Tooltip />
          <Bar dataKey="product" fill="#2563eb" name="Product" />
          <Bar dataKey="services" fill="#16a34a" name="Services" />
        </BarChart>
      </ResponsiveContainer>
    </div>
  );
}

Add <Legend /> when color alone is not enough to identify series. Keep category names short or rotate dense tick labels; excessive labels make a narrow chart unreadable.

Stacked bars for part-to-whole data

Use the same stackId on bars that belong in one stack:

<Bar dataKey="new" stackId="total" fill="#2563eb" name="New" />
<Bar dataKey="returning" stackId="total" fill="#f59e0b" name="Returning" />

Stacking answers “what makes up this total?” Grouping answers “which series is larger?” Do not stack merely to save space when readers need accurate, direct comparisons between individual series. For percentages, ensure each category uses the same denominator and label the axis accordingly.

Scale, labels, and visual accuracy

The default numeric axis usually starts at zero, which is appropriate for counts and amounts where bar length represents magnitude. A truncated domain can exaggerate small differences; if you intentionally change the domain, explain the scale and consider a non-bar chart for near-equal values. Configure ticks and domains on YAxis only when the data and available width justify it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The Bar API supports labels, active-bar styling, animation controls, minimum point size, and custom SVG-compatible labels. A custom label must render SVG elements such as <text>; an HTML <div> is invalid inside the chart’s SVG. For example:

<Bar dataKey="value" fill="#2563eb" label={{ position: 'top' }} />

Use labels when there are few bars and exact values matter. For many bars, a tooltip plus a data table is less cluttered. Set a minimum point size only when very small nonzero values would otherwise disappear, and make clear that the visual height has been enlarged.

Accessibility that survives real use

Recharts 3 enables accessibilityLayer by default. For supported Cartesian charts such as BarChart, this adds keyboard navigation and screen-reader support. Do not treat that layer as a substitute for meaningful content:

  • Give the chart a visible heading, such as “Quarterly orders by channel.”
  • Keep visible axis labels and include units in the heading or axis label.
  • Provide a text alternative or an HTML table when the values matter beyond visual comparison.
  • Use a color palette that remains distinguishable without color vision and keep the legend labels explicit.

The default tooltip can act as a live region. If you replace it, expose concise updates with role="status" and aria-live="assertive"; avoid announcing every minor pointer movement as a long paragraph. Test keyboard focus and screen-reader output with the actual chart, not only with a static screenshot.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Animation, server rendering, and reduced motion

For a server-rendered application, isAnimationActive="auto" disables animation during SSR and respects the user’s prefers-reduced-motion preference. You can turn animation off explicitly for dashboards that update frequently:

<Bar dataKey="value" fill="#2563eb" isAnimationActive={false} />

Animation can help show a data update, but it should not delay access to values or create motion for users who have requested less motion. Keep transitions short and avoid animating dozens of series simultaneously.

Common failures and fixes

The chart is blank

Check that the parent has a nonzero height, the data array is not empty, and every dataKey matches the property name exactly. Log the data immediately before rendering and inspect the element’s computed dimensions.

Bars have no useful labels

Use XAxis dataKey="yourCategory" and set a clear name on each Bar. Long categories need abbreviated display values, rotated ticks, or a wider chart.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Responsive resizing fails

Verify that every ancestor between the chart and the page has a resolved width and height. A hidden tab, collapsed flex item, or percentage height without a fixed ancestor commonly measures as zero. Add a ResizeObserver polyfill for browsers that lack it.

Custom labels break rendering

Render SVG-compatible nodes, not HTML elements, inside the chart. Start with the built-in label option before writing a custom label component.

Server and client markup differ

Disable animation for SSR or use the documented automatic setting. Ensure the server and client receive the same data and dimensions; do not read browser-only measurements during the server render.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is to capture the finished chart for documentation, regression checks, or a report, ScreenshotNeo can render the page through one API call. It accepts cookie and consent banners before capture, removes more than 60 known consent platforms plus newsletter popups and chat widgets, and bills only clean shots. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; the response identifies the page verdict and billing status in X-Page-Verdict and X-Billed headers.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

After deploying the React page at a reachable URL, request an image:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The same request in Python is:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

In Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo documentation for capture options. It can wait for a selector or network idle, load lazy images, set a viewport or device preset, use dark mode and retina scale, hide selectors, run custom CSS or JavaScript, and capture a selected element. PDF output, signed links, asynchronous jobs, webhooks, bulk capture of up to 100 URLs per call, caching with a chosen TTL, and custom headers, cookies, user agents, authorization, timezone, and geolocation are also available. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan. Create a free ScreenshotNeo account to try it.

Final implementation checklist

  • Install Recharts and verify the package version used by your lockfile.
  • Give the chart parent a definite, responsive height.
  • Choose grouped or stacked bars based on the comparison question.
  • Label axes, units, series, and the chart heading.
  • Keep a text alternative or table for important values.
  • Use SVG-compatible custom labels and respect reduced-motion preferences.
  • Test empty data, long labels, narrow screens, hidden tabs, SSR, and keyboard navigation.

Frequently Asked Questions

Can I use Recharts in a React server-rendered app?

Yes. Keep server and client data consistent, and use the automatic animation setting or disable animation so the rendered markup and motion behavior are appropriate for SSR.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should a bar chart start its axis at zero?

Usually yes, because bar length encodes magnitude. Change the domain only when you have a clear reason and make the scale conspicuous to readers.

When should I use grouped instead of stacked bars?

Use grouped bars for direct side-by-side comparisons between series. Use stacked bars when the composition of a category total is the main question.

What should replace a chart for screen-reader users?

Keep the chart, but provide a concise text summary or an HTML data table containing the values and units.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.