Gauge Chart
- Stable
- WCAG 2.2 evidence
- RTL
A semicircular gauge: one reading on a scale, as an arc filled from the start to the value, a marker for a
benchmark, the value in the middle and the ends of the scale under the arc. Data driven: value, min, max, benchmark and bands
in, SVG out; the same props render the static SVG on the server. Accessibility: the plot is a meter (role="meter" with aria-valuemin, aria-valuemax, aria-valuenow and a text value in
aria-valuetext, named by the title), because a gauge is one scalar in a known range; not the React Aria Meter, which sets
role="meter progressbar" and axe rejects. The figure is named by title, described by summary and backed by a data table with
the value, the ends, the benchmark, the band and the band ranges (WCAG 1.1.1, 1.3.1, 4.1.2). The meter is a tab stop: focusing or
hovering it shows a tooltip that stays while hovered and closes with Escape (1.4.13, 2.1.1). Meaning is never colour alone: the value
is text in the hole, the benchmark is a marker with a text label, and bands are gaps with labelled boundaries and a named status
(1.4.1). The draw-in is behind motion-safe:. The arc follows the container width and the end labels stay under its ends (1.4.10);
the plot stays left-to-right in right-to-left pages while the card and table mirror, and digits follow the locale. Consumer duties: a title that asks the question, a summary with the main message, units and the sign in valueFormat
({ signDisplay: "exceptZero" } gives "+42"), band names that say what the ranges mean.
import { GaugeChart } from "@nexera-ui/react";- 10
- examples
- 25
- props
- 3
- live controls
- 1
- platform
- 10
- WCAG criteria
- 1
- block uses it
Try every prop. Copy the code.
Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.
import { GaugeChart } from "@nexera-ui/react";
<GaugeChart />Examples 9
The same examples as Storybook, rendered live. Open Code to copy one.
Without bands
Without bands the arc is one piece; the caption names only the benchmark.
import { GaugeChart } from "@nexera-ui/react";
<GaugeChart bands={[]} />;
Percentage
A plain percentage: no benchmark, no bands, the scale starts at 0.
import { GaugeChart } from "@nexera-ui/react";
<GaugeChart
title="Profile completion"
description="All employees"
summary="86 percent of employee profiles are complete."
value={0.86}
min={0}
max={1}
valueFormat={{ style: "percent" }}
benchmark={{ value: 0.8, label: "target" }}
bands={[]}
/>;
At the edges
A reading at the start of the scale draws no value arc; a reading outside the scale sits at the end, and the text keeps the real number.
import { GaugeChart } from "@nexera-ui/react";
export function AtTheEdges() {
return (
<div className="flex flex-wrap gap-4">
<div className="w-72 max-w-full">
<GaugeChart
title="At the start"
summary="The score is -100."
value={-100}
min={-100}
max={100}
valueFormat={{ signDisplay: "exceptZero" }}
/>
</div>
<div className="w-72 max-w-full">
<GaugeChart
title="Past the end"
summary="The score is 130, past the +100 scale."
value={130}
min={-100}
max={100}
valueFormat={{ signDisplay: "exceptZero" }}
/>
</div>
</div>
);
}
Currency
Large numbers and currency: the ends of the scale shorten to "Rs 0" and "Rs 50M", the headline shrinks to fit the hole.
import { GaugeChart } from "@nexera-ui/react";
<GaugeChart
title="Payroll against budget"
description="September 2026"
summary="Payroll is Rs 29,043,000 of the Rs 50M budget."
value={29_043_000}
min={0}
max={50_000_000}
valueFormat={{ style: "currency", currency: "PKR", maximumFractionDigits: 0 }}
locale="en-PK"
benchmark={{ value: 35_000_000, label: "last year" }}
bands={[
{ from: 0, label: "Under budget" },
{ from: 40_000_000, label: "Near the limit" },
]}
/>;
Loading
Loading, empty and error are ChartStates inside the card; the header stays.
import { GaugeChart } from "@nexera-ui/react";
<GaugeChart state={{ status: "loading" }} />;
Empty
import { GaugeChart } from "@nexera-ui/react";
<GaugeChart
value={null}
state={{
status: "empty",
title: "No survey results yet",
description: "The pulse survey closes on Friday.",
}}
/>;
Error state
import { Button, GaugeChart } from "@nexera-ui/react";
<GaugeChart
state={{
status: "error",
title: "Couldn't load eNPS",
description: "Check your connection and try again.",
action: (
<Button variant="secondary" size="sm">
Try again
</Button>
),
}}
/>;
Long labels
Long band and benchmark names wrap in the caption, the tooltip and the table.
import { GaugeChart } from "@nexera-ui/react";
<GaugeChart
title="Employee net promoter score across all offices and remote teams"
summary="The score is above the benchmark of the national industry association."
benchmark={{ value: 31, label: "national industry association benchmark" }}
bands={[
{ from: -100, label: "Needs urgent attention from leadership" },
{ from: 0, label: "Acceptable" },
{ from: 30, label: "Well above the benchmark set by the industry association" },
]}
/>;
Right to left
Right-to-left page: the card and table mirror, the arc keeps its left-to-right scale, digits follow the locale.
import { GaugeChart } from "@nexera-ui/react";
<GaugeChart
title="مؤشر صافي الترويج للموظفين"
description="استطلاع الربع الثالث 2026"
summary="بلغ المؤشر ٤٢+، أعلى من معيار القطاع البالغ ٣١+."
benchmark={{ value: 31, label: "القطاع" }}
bands={[
{ from: -100, label: "ضعيف" },
{ from: 0, label: "مقبول" },
{ from: 30, label: "جيد" },
]}
labels={{
value: "القيمة",
min: "الحد الأدنى",
max: "الحد الأقصى",
benchmark: "المعيار",
status: "الحالة",
}}
table={{ categoryLabel: "البند", label: "عرض البيانات كجدول" }}
/>;
Props 25
Press "Try it" on a card to load that prop into the playground.
25 props shown
value*Nexeranumber | nullThe reading. null is no reading: the empty state shows instead. A value outside min to max is drawn at the end
of the arc; the text and the table keep the real number.
minNexeranumberThe value at the start of the arc.
maxNexeranumberThe value at the end of the arc.
benchmarkNexeraGaugeBenchmarkA reference value marked on the arc.
bandsNexerareadonly GaugeBand[]Named ranges of the scale, for a reading that means something ("Poor", "Fair", "Good"). Each band after the first splits the arc with a gap and a labelled boundary; the band the value is in is named in the caption, the meter's text value, the tooltip and the table, so the meaning is never told by position or colour alone (WCAG 1.4.1). Order does not matter.
valueTextNexerastringThe text value of the meter, read by assistive technology after the name ("+42, Good, industry +31").
centerValueNexeraReactNodeThe headline under the arc. A string or number shrinks to fit the hole.
centerLabelNexeraReactNodeThe caption under the headline.
isCenterHiddenNexerabooleanLeave the hole empty. The text value stays on the meter for assistive technology.
labelsNexeraGaugeLabelsThe words for the tooltip and the table. Translate them.
title*NexerastringChart title: the question the chart answers ("Headcount"). Required: it names the figure, the plot and the data table (WCAG 1.1.1).
descriptionNexeraReactNodeSecondary line under the title.
summary*NexerastringOne or two sentences with what the chart shows and its main message ("Headcount grew from 96 to 128 over twelve months"). Required: it describes the figure for assistive technology (WCAG 1.1.1); the data table has the details.
rangeNexeraChartRangePropsRange switch in the header: 3M, 6M, 12M. Pass the data of the chosen range back in.
actionsNexeraReactNodeExtra controls in the header, after the range switch.
kpiNexeraChartKpiPropsKPI row above the plot: the headline number with an optional label or change badge.
stateNexeraChartPlotStateThe state that replaces the plot: loading (skeleton), empty or error. A chart without a value to plot shows the empty state
by itself; pass { status: "empty", title, description, action } to give it your wording.
tableNexeraChartTableOptionsThe data table that is the text alternative: caption, first-column header and whether it is visible or only for assistive technology.
localeNexerastringLocale of digits and separators.
valueFormatNexeraNumberFormatOptionsIntl.NumberFormat options for values ({ style: "currency", currency: "PKR" }, { style: "percent" }). Serialisable, so it
works from a Server Component; formatValue needs a Client Component.
formatValueNexera(value: number) => stringFormats a value for tooltips, point labels and the table (full precision). Wins over valueFormat.
formatAxisValueNexera(value: number) => stringFormats an axis tick (short: "29M").
heightNexeranumberHeight of the plot in px. The card grows with the header, KPI and legend around it.
plotLabelNexerastringAccessible name of the plot group. Translate it.
noDataLabelNexerastringText for a missing value in the tooltip and the table. Translate it.
* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.
Accessible by default.
Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.
WCAG 2.2 evidence
8 direct · 2 supporting- 1.1.1Non-text ContentLevel A · tested directly
- 1.3.1Info and RelationshipsLevel A · tested directly
- 1.4.1Use of ColorLevel A · tested directly
- 1.4.10ReflowLevel AA · tested directly
- 1.4.13Content on Hover or FocusLevel AA · tested directly
- 2.1.1KeyboardLevel A · tested directly
- 2.3.3Animation from InteractionsLevel AAA · supporting test
- 2.4.7Focus VisibleLevel AA · supporting test
- 4.1.2Name, Role, ValueLevel A · tested directly
- 4.1.3Status MessagesLevel AA · tested directly
Fits any width.
Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.
Styling hooks
Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.
<GaugeChart className="shadow-sm" />Used in blocks
Related components
- AccordionItemOne collapsible section of an FAQ or settings page.
- AreaChartA stacked area chart: layers piled up over time with the title, range switch, actions and legend of the card.
- AvailabilityRowOne person's availability across a window of the day: an avatar with initials and the name, and a timeline with the busy periods drawn as bars.
- AvatarA person or organisation shown as a photo, initials or an icon.
- AvatarGroupA row of overlapping avatars with a "+N" chip for the rest.
- AvatarLabelAn avatar with a name and an optional subtitle beside it, for a person in a list, a header or a mention.
- BadgeShort status or category label: `Tone` x `Variant` x `Size`, with an optional dot, leading icon and remove button.
- BadgeGroupA pill that pairs a small badge with a short message, for an announcement or a status line.