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.

The most practical way to make a bar graph in React.js is to install Recharts and compose its declarative BarChart, Bar, axis, grid, tooltip and responsive components. The example below starts with a working chart, then covers responsive sizing, grouped and stacked data, accessibility, production behavior, troubleshooting and an API alternative for rendered screenshots.

Build a working React bar graph

Recharts is a React-and-D3 chart library with native SVG output and composable components. Create or open a React application, install the package, and add a chart component.

npm install recharts

The following component is runnable in a current React project:

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

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

export default function Example() {
  return (
    <section aria-labelledby="sales-chart-title">
      <h2 id="sales-chart-title">Quarterly values</h2>
      <div style={{ width: '100%', height: 320 }}>
        <ResponsiveContainer width="100%" height="100%">
          <BarChart data={data} margin={{ top: 16, right: 20, left: 8, bottom: 8 }}>
            <CartesianGrid strokeDasharray="3 3" />
            <XAxis dataKey="name" />
            <YAxis />
            <Tooltip />
            <Legend />
            <Bar dataKey="value" name="Value" fill="#2563eb" />
          </BarChart>
        </ResponsiveContainer>
      </div>
    </section>
  );
}

dataKey tells each axis or bar which object property to read. Keep numeric values as numbers, not formatted strings, so scales, tooltips and sorting work correctly.

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

Use a fixed chart height in the layout

ResponsiveContainer measures its parent with the browser’s ResizeObserver. A percentage width is useful only when the parent has a usable height. Without one, the chart can render at zero height.

.chart-frame {
  width: 100%;
  height: 320px;
}

@media (max-width: 600px) {
  .chart-frame { height: 240px; }
}

Projects that must support browsers without ResizeObserver need a compatible polyfill. Alternatively, use the responsive option on BarChart when your CSS sizing strategy already supplies dimensions.

Choose grouped or stacked bars

Grouped bars for side-by-side comparison

Give each series its own Bar. This makes values for the same category easy to compare directly.

const data = [
  { month: 'Jan', desktop: 120, mobile: 90 },
  { month: 'Feb', desktop: 140, mobile: 110 },
  { month: 'Mar', desktop: 130, mobile: 125 }
];

<BarChart data={data}>
  <XAxis dataKey="month" />
  <YAxis />
  <Tooltip />
  <Legend />
  <Bar dataKey="desktop" fill="#2563eb" />
  <Bar dataKey="mobile" fill="#16a34a" />
</BarChart>

Stacked bars for part-to-whole relationships

Use the same stackId on bars that form one total. Stacking is appropriate for composition, such as paid versus organic traffic, but can make individual segment comparisons harder.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<Bar dataKey="paid" stackId="total" fill="#7c3aed" />
<Bar dataKey="organic" stackId="total" fill="#f59e0b" />

Decide based on the question your reader must answer: side-by-side differences favor grouping; contribution to a total favors stacking. Also consider the number of series, label density and available width.

Make scales and labels truthful

Set a deliberate domain

The default Y-axis domain is calculated from the data. For values where a zero baseline matters, explicitly include zero:

<YAxis domain={[0, 'dataMax']} />

For percentages or known limits, use a fixed domain such as [0, 100]. Avoid truncating a bar chart’s baseline unless the visual treatment is clearly disclosed; a shortened baseline can exaggerate small differences.

Format ticks and tooltips

const number = new Intl.NumberFormat('en-US');

<YAxis tickFormatter={(value) => number.format(value)} />
<Tooltip formatter={(value) => number.format(value)} />

Long category names need shorter labels, rotated ticks or a wider chart. Do not remove visible axis labels merely to avoid overlap; they provide context that a color legend cannot replace.

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

Add values on bars safely

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

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

Use minPointSize carefully: it improves visibility for tiny nonzero values but changes their visual length. Explain that choice in the surrounding text when precision is important.

Accessibility for React bar charts

Recharts 3 enables accessibilityLayer by default for supported Cartesian charts, including BarChart. It adds keyboard navigation and screen-reader support. Keep the default enabled unless you have a tested reason to change it.

Provide context outside the SVG

  • Give the chart a meaningful heading, as in the example’s aria-labelledby relationship.
  • Keep visible X- and Y-axis labels and units.
  • Use sufficient color contrast and do not encode the only distinction with color.
  • Provide a text alternative or data table when exact values matter.

Keep tooltip announcements concise

The default tooltip acts as a live region. If you replace it, expose a concise status rather than dumping every datum into an announcement:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
function AccessibleTooltip({ active, payload, label }) {
  if (!active || !payload?.length) return null;
  return (
    <div role="status" aria-live="polite">
      {label}: {payload[0].value}
    </div>
  );
}

Use aria-live="assertive" only when an update genuinely requires immediate interruption. Test keyboard focus, screen-reader output and reduced-motion settings with the actual data and labels used in production.

Responsive behavior and mobile layouts

  1. Give the chart wrapper a real height in pixels, rem or another resolvable CSS unit.
  2. Set ResponsiveContainer width="100%" height="100%" inside that wrapper.
  3. Reserve horizontal space for Y-axis ticks, legends and margins.
  4. On narrow screens, shorten category labels or provide a horizontal scrolling region rather than allowing text to collide.
  5. Verify the chart after sidebars open, fonts load and the layout changes; these events trigger ResizeObserver measurements.

If the chart is conditionally rendered in a hidden tab or collapsed panel, measure it after it becomes visible. A zero-width measurement can persist until the parent resizes.

Animation, server rendering and performance

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

<Bar dataKey="value" isAnimationActive={false} />

For large datasets, aggregate values before rendering, avoid recreating large arrays on every render, and render only the series users need. A bar chart is a poor fit for thousands of individual categories; paginate, filter or switch to a visualization designed for dense data. Memoize expensive data preparation, but do not memoize blindly—measure the actual render path.

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

Common failures and fixes

Nothing appears

  • Parent has no height: add a definite height to the wrapper.
  • Parent is hidden: render or resize after the tab, dialog or accordion opens.
  • Wrong key: ensure dataKey exactly matches the object property and values are numeric.

Bars are all zero or malformed

Check for strings such as "1,200", null values and inconsistent property names. Normalize API data before passing it to Recharts:

const chartData = apiRows.map((row) => ({
  name: row.label,
  value: Number(row.amount) || 0
}));

Labels overlap or disappear

Increase chart width, rotate or abbreviate ticks, adjust margin, or move the legend. For a custom label, return SVG nodes—not HTML—and confirm its coordinates remain inside the plot area.

Tooltip or keyboard behavior is confusing

Keep the accessibility layer enabled, supply a chart title, and test focus order. Replace the tooltip only when the custom component preserves a concise live-region announcement.

Animation causes motion or hydration differences

Honor reduced-motion preferences and use isAnimationActive={false} when deterministic output is more important than transition effects. In server-rendered applications, rely on the documented automatic behavior or disable animation explicitly.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Capture a React chart for documentation or testing

A browser screenshot is useful for visual regression tests, release notes and support tickets. Capture the fully loaded state, including any data-fetching completion and responsive breakpoint you want to verify. If you need a PDF, use a browser print flow or an API that renders the page rather than trying to convert SVG manually.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP tools—take_screenshot, get_page_info and capture_pdf—work with Claude, Cursor and other MCP clients.

One GET request returns PNG, JPEG, WebP or PDF. See the ScreenshotNeo API documentation for all options, including viewport and device presets, full-page lazy-image loading, CSS-selector element capture, custom JavaScript and CSS, waits, headers, cookies, blocking rules, geolocation, dark mode, resizing, caching, signed links, asynchronous webhooks and bulk capture.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free, and every feature is included on every plan. Create a free ScreenshotNeo account.

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

Frequently Asked Questions

Can I use Recharts with TypeScript?

Yes. Define an interface for each row and type the data array before passing it to the chart; the Recharts component props then catch misspelled keys during development.

Should a bar chart start at zero?

Usually, yes when bar length represents magnitude. Use a nonzero domain only for a deliberate analytical comparison and make the scale visible so readers are not misled.

How do I show an empty state?

Check the data array before rendering the chart and display an explanatory message such as “No values for this period.” Do not render an axis-only chart that implies zero data.

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.

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