Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelog
  1. Home
  2. Blog
  3. Component guides
  4. React Gauge Chart: Zones, Targets and Small Sizes
Auf Deutsch lesen
  1. Blog
  2. Component guides
  3. React Gauge Chart: Zones, Targets and Small Sizes
Component guides
Component guides

React Gauge Chart: Zones, Targets and Small Sizes

SR
Serban Rusu · Founder of Wingo UI
Oct 19, 2026 · 9 min read

On this page

0%
  1. When should I use a gauge chart instead of a bar or a ring?
  2. Which React gauge chart packages exist?
  3. What props does a React gauge chart need?
  4. How do I keep a gauge readable at small sizes?
  5. How do I show a lower-is-better value?
  6. How do I show several goals as a React radial progress chart?
  7. How do I make a gauge chart accessible?
  8. What are the common gauge chart pitfalls?
  9. How do I add it to my project?
  10. FAQ
    1. How do I make a gauge chart in React?
    2. What is the difference between a gauge and a radial bar chart?
    3. Which ARIA role should a gauge use?
    4. Can I use a React gauge chart in Next.js with server rendering?
    5. Are the Wingo UI Gauge and Radial Bar free?

TL;DR

A React gauge chart shows one value on a fixed scale: an arc, a needle or segments, colored by the zone the value is in, with a target tick and a label that has to stay readable when the dial shrinks to 120px. Use a gauge for one number against zones, radial bars for several goals that each fill toward their own target, and a plain progress ring when you only need a percent. The Wingo UI Gauge and Radial Bar do this from props and announce themselves as meters to screen readers.

Published Oct 19, 2026

You need a React gauge chart for a dashboard: sales against the monthly goal, an NPS score, a support SLA, disk usage. One number, a scale, and a sense of whether that number is good or bad. The first version is usually an SVG arc with a big number in the middle, and it looks fine at 280px. Then it lands in a KPI card at 120px, the label overflows the bowl, the min and max collide with the arc ends, and a screen reader announces an unlabeled image. This guide covers when a gauge is the right chart, the props that matter in the Wingo UI Gauge and Radial Bar, and how to keep both readable on a phone.

When should I use a gauge chart instead of a bar or a ring?

Use a gauge when a single value sits on a scale with a meaningful minimum and maximum and the zones matter as much as the number. A speedometer has a red zone; a monthly goal has "behind", "close" and "good". If you only need a percent of a task, a progress bar or ring says the same thing in less space. If you have several goals at once, radial bars compare them better than a row of gauges.

You want to showUseWhy
One value against zones and a target (NPS, SLA, quota)GaugeZone colors, a target tick and the scale ends in one dial
Several goals, each with its own targetRadial BarConcentric rings compare progress, and a ring past 100% laps
One percent of a task (upload, onboarding)Progress ringSmaller, free, announced as a progressbar
A number and its trendStat CardA gauge has no time axis

The WAI-ARIA meter pattern (opens in a new tab) draws the same line: a meter is a value within a known range, such as a battery level, and it should not be used for progress or for values without a meaningful maximum. That is a good test for any gauge. If you cannot name the max, pick another chart.

Which React gauge chart packages exist?

Three names come up first when you search for a react gauge chart component or a react speedometer chart, plus MUI X if you already use MUI. Facts are from each project's npm entry and docs, as of October 2026.

PackageLatest versionLicenseNotes from the docs
react-gauge-chart (opens in a new tab)0.5.1, published April 2024MITD3 based. nrOfLevels or arcsLength for zones, percent from 0 to 1 for the needle. Its peer dependencies stop at React 18. The README calls a re-render at a different size on prop updates a bug and suggests a fixed height.
react-gauge-component (opens in a new tab)2.0.29, published April 2026MITA fork of react-gauge-chart with a preset gallery and a sandbox editor. Peer dependencies include React 19. The README shows a dynamic import with ssr: false for Next.js.
react-d3-speedometer (opens in a new tab)3.1.2, published January 2026MITA needle speedometer built on D3, with React 19 as its peer dependency.
MUI X Charts Gauge (opens in a new tab)@mui/x-charts 9.15.0, published October 2026MITArc gauge with value, valueMin, valueMax, startAngle, endAngle. Follows the meter ARIA pattern. There is no needle prop: the docs draw one inside GaugeContainer with the useGaugeState() hook.

If you already ship MUI, its Gauge is the obvious choice: it is accessible and you add no new dependency. If you want a needle gauge with zones from one npm install and do not mind a client-only import, pick react-gauge-component over react-gauge-chart: it had a release in April 2026 and lists React 19 as a peer. The Wingo UI Gauge is source you copy into your project, with zones, a target and three variants built in.

What props does a React gauge chart need?

A value, a scale and zones. value is required, min and max default to 0 and 100, and thresholds lists where each zone starts. Zones are sorted for you, and each one runs to the next threshold or to max.

bash
npx wingo-ui@latest add gauge
tsx
import { Gauge } from "@/components/ui/gauge";
export function SalesGoal() {
return (
<Gauge
value={67.6}
valueFormat="percent"
target={75}
thresholds={[
{ value: 0, tone: "danger", label: "Behind" },
{ value: 50, tone: "warning", label: "Close" },
{ value: 75, tone: "success", label: "Good" },
]}
label="Monthly sales goal"
description="$6,760 of $10,000"
locale="en-US"
/>
);
}

The arc takes the tone of the zone the value is in (colorByZone, on by default), a thin band outside the arc shows every zone (showBands), and a chip under the value names the current zone. target draws a tick across the track that is cut into the surface color, so it reads over any zone color.

The props you will change next:

  • variant: arc fills the track up to the value, needle draws a thin zone-colored track and a needle (the react speedometer chart look), segments splits the track into zones or into segments equal steps.
  • sweep: 180 for a half circle, 240 (the default) or 270 for an open ring.
  • size: sm, md or lg, a nominal width of 120, 200 or 280px with the value at 18, 28 or 40px.
  • valueFormat: number, compact, currency or percent, with currency and locale. For anything else, formatValue(value, { kind }) gets "value", "tick" for the min and max, or "label" for the spoken text.

Drag the slider below the dial. The arc changes color as the value crosses 50% and 75%, and the dollar line under the label follows it.

Drag the slider: the arc turns amber at 50% and green at 75%, the zone chip changes, and the number counts to the new value
$ npx wingo-ui@latest add gauge
ProGauge docs

How do I keep a gauge readable at small sizes?

Let the component make room for the text. Most gauge examples put the value, the label and the description in the bowl at a fixed font size. That works at 280px and breaks at 120px, where a label like "Average reply time" is wider than the hole.

The Gauge handles this in three steps, all without measuring the DOM:

  1. The value shrinks to fit. The big number scales down when its formatted text is wider than the space inside the arc, so "$128,450" never touches the track.
  2. The label moves under the dial when the label and description would run into the min and max row. It first tries a narrower column between the two scale ends, and only moves out when that is still too tall. The value stays in the bowl.
  3. The scale ends turn compact. With valueFormat="currency" and a range of 10,000 or more, a max of 190000 prints as "$190K" under the arc end.

Because the layout comes from estimated text widths, the server HTML already has everything in place, and nothing jumps on hydration. The dial also shrinks with a narrower container, but the root carries min-w-[120px], so a two-column grid of gauges fits a 360px phone and a third column does not.

For list rows, a half circle reads better than a 240-degree arc, because it is shorter. Hide the scale ends, put the label text next to the dial, and pass min-w-0 with a width when the row needs the dial below 120px:

tsx
<Gauge value={42} max={60} size="sm" sweep={180} showMinMax={false} tone="info" locale="en-US" className="w-[96px] min-w-0" />

How do I show a lower-is-better value?

List the zones from good to bad. Response times, error rates and costs are better when they are low, so the first zone is the success tone:

tsx
"use client";
import { Gauge } from "@/components/ui/gauge";
const hours = (v: number) => `${v.toLocaleString("en-US", { maximumFractionDigits: 1 })} h`;
export function ReplyTime({ value }: { value: number }) {
return (
<Gauge
value={value}
max={8}
variant="segments"
target={4}
thresholds={[
{ value: 0, tone: "success", label: "Fast" },
{ value: 4, tone: "warning", label: "Slow" },
{ value: 6, tone: "danger", label: "Critical" },
]}
label="Average reply time"
description="Goal: under 4 h"
formatValue={(v) => hours(v)}
/>
);
}

The "use client" line matters here: formatValue is a function, and a Server Component cannot pass a function to a Client Component. The segments variant shows each zone as its own piece, the current one solid and the others at 25%, with a ring marker at the value. For a score with a negative range, such as NPS from -100 to 100, set min={-100} and max={100} and the zones work the same way. Values outside the range are clamped for drawing while the text still shows the real number, and value={null} draws the track with a dash for "no data yet".

The needle variant on a half circle: drag the slider and the needle turns through the zones while the value counts
$ npx wingo-ui@latest add gauge
ProGauge docs

How do I show several goals as a React radial progress chart?

Use the Radial Bar. A react radial progress chart with several rings answers a different question than a gauge: how far along is each goal, side by side. Each item in data is a ring with its own max, outermost first.

bash
npx wingo-ui@latest add radial-bar
tsx
"use client";
import { useState } from "react";
import { RadialBar, type RadialBarDatum } from "@/components/ui/radial-bar";
const goals: RadialBarDatum[] = [
{ id: "calls", label: "Calls", value: 42, max: 60 },
{ id: "meetings", label: "Meetings", value: 7, max: 10 },
{ id: "quotes", label: "Quotes sent", value: 18, max: 15 },
];
export function TeamActivity() {
const [selected, setSelected] = useState<string | null>(null);
return (
<RadialBar
data={goals}
value={selected}
onValueChange={setSelected}
label="Team activity today"
description="Quotes sent passed its target"
center={<span className="text-xl font-semibold">3 goals</span>}
locale="en-US"
/>
);
}

A ring past its target keeps going for a second lap, so 18 of 15 quotes reads as more than done without breaking the scale. variant="bars" draws 270-degree bars instead of full rings, each named just left of its start at 12 o'clock. The legend sits beside the chart from 480px of container width and moves below it on narrower containers.

Small sizes are handled the same way as on the Gauge. size takes sm, md, lg or any number of pixels, so a 52px ring set fits a list row. When the hole is too small for a readout, the hovered or focused ring's value floats beside its end instead, and on touch screens it is pinned above the chart (tooltipMode="auto").

Hover or tap a ring: the others dim and the hole shows its percent. Tab to the chart and use the arrow keys to walk the rings
$ npx wingo-ui@latest add radial-bar
ProRadial bar docs

How do I make a gauge chart accessible?

Give it the meter role, a name and a sentence that a person can understand. The Gauge renders role="meter" with aria-valuemin, aria-valuemax and aria-valuenow. A string label names it; other label nodes are linked through aria-labelledby, and description through aria-describedby. The spoken value includes the zone and the target, for example "67.6%, Close zone, target 75%". Replace that sentence with labels.valueText(value, min, max, info), where info has the formatted text, the zone and the target. The gauge is read-only and never takes focus, because there is nothing to operate.

The Radial Bar is interactive, so it works differently. It renders a hidden meter per ring, a screen reader table with value, target and percent, and keyboard support: Tab to the chart, arrow keys walk the rings, Home and End jump to the outermost and innermost one, Enter or Space selects, Escape clears. A live region reads each ring as you move.

Color alone never carries the zone on either chart. The Gauge prints the zone name in the chip and in the spoken text; the Radial Bar prints values and percentages in the legend. Under reduced motion both skip the sweep and show the final state.

What are the common gauge chart pitfalls?

  • A gauge for a number without a max. Revenue this month has no natural ceiling. Use a goal as the max, or show a stat card with a trend.
  • The target notch on a different background. The tick is cut in the surface color. If the gauge sits on a card or a custom fill, pass that color as surface.
  • Zone labels left out. Without label on each threshold, the chip disappears and screen readers hear the number and the target but not the zone.
  • Animation in thumbnails and print. The arc sweeps in the first time it scrolls into view. Pass animated={false} for static exports.
  • A row of gauges for related goals. Five dials side by side are hard to compare. Radial bars or a bar chart put them side by side in one chart.

How do I add it to my project?

Run npx wingo-ui@latest add gauge or npx wingo-ui@latest add radial-bar. The CLI copies the source into your project, adds the chart kit, motion and number helpers they import, and installs motion and d3-shape. Both are Pro components (pricing); the Progress ring is free if one percent is all you need. For the screen around a gauge, the Next.js admin dashboard tutorial builds the shell, KPI row and tables, and the dashboard component library comparison covers the rest of the chart set. More single-component deep dives are in the component guides category, including the React sparkline guide for trends inside KPI tiles.

Components in this post

  • Gauge

    A React gauge chart showing one value against a scale and its zones: a speedometer arc, needle or segmented dial with a target tick.

    Pro
  • Radial bar

    A React radial bar chart: several goals as concentric activity rings or 270° bars, each filling toward its own target and lapping past 100%.

    Pro

FAQ

How do I make a gauge chart in React?

Use a gauge component that takes a value, a min and a max, then add zones and a target. With Wingo UI that is , installed with npx wingo-ui@latest add gauge.

What is the difference between a gauge and a radial bar chart?

A gauge shows one value on a scale with zones, like a speedometer. A radial bar chart shows several values as concentric rings, each filling toward its own target, like fitness activity rings.

Which ARIA role should a gauge use?

role="meter" with aria-valuenow, aria-valuemin, aria-valuemax and a label, as described in the WAI-ARIA Authoring Practices meter pattern. Use progressbar instead when the value is task progress, such as an upload.

Can I use a React gauge chart in Next.js with server rendering?

Some packages need a dynamic import with ssr set to false; the react-gauge-component README shows that for Next.js. The Wingo UI Gauge places its text from estimated widths instead of measuring the DOM, so the server HTML already has the dial, the value and the label in place.

Are the Wingo UI Gauge and Radial Bar free?

No. Both are Pro components. The Progress component, which has a ring variant for a single percent, is in the free tier.

  • Charts
  • Gauge
  • Dashboard
  • Accessibility
  • React

Share

SR

About the author

Serban Rusu

Founder of Wingo UI

Serban Rusu founded Wingo UI. He builds its component library, CLI and MCP server, and writes about React interfaces for phones and AI coding agents.

More from Serban
Keep reading

Related posts

All posts
Component guides

Embla Carousel React: Accessible Slides, No Layout Shift

Build an embla carousel react component for photos, listings, testimonials and onboarding, with keyboard controls, pausable autoplay and no layout shift.

SRSerban Rusu·Oct 19, 2026·9 min read
Component guides

React Animated Number Counter: Rolling Odometer Digits

Build a React animated number counter that rolls each digit like an odometer, takes its separators from Intl, holds its width and respects reduced motion.

SRSerban Rusu·Oct 19, 2026·9 min read
Component guides

React Audio Player with Waveform: Scrub, Seek, Peaks

Build a React audio player with waveform scrubbing for podcasts, chat voice notes and call logs, with keyboard seek, precomputed peaks and no layout shift.

SRSerban Rusu·Oct 19, 2026·9 min read
Newsletter

Get new posts by email

New guides, tutorials and comparisons from the Wingo UI blog, sent when they are published.

No spam. Unsubscribe at any time.

WingoUI

Animated, configurable, mobile-first React components and blocks. Copy the source, make it yours, and let your coding agent build with it.

Product

  • Components
  • Templates
  • Pricing
  • AI agents
  • Theme generator

Resources

  • Docs
  • Blog
  • Changelog
  • Changelog RSS
  • llms.txt

Legal

  • Terms
  • Privacy
  • Refunds
  • License
  • Imprint

Component categories

  • Buttons & Actions
  • Inputs
  • Forms
  • Navigation
  • Overlays
  • Feedback
  • Data Display
  • Tables & Lists
  • Charts & Stats
  • Layout
  • Media
  • AI Kit
  • Text & Effects
  • Mobile
  • Commerce
  • Marketing Sections
  • Blocks
  • Hooks & Utilities

© 2026 Wingo UI

Wingo UI