Radar Chart
- Stable
- WCAG 2.2 evidence
- RTL
A radar chart: several measures of one thing on spokes round a circle, each series a polygon, with the
axes named and a list of the values beside it. Data driven: categories and series in, SVG out; the same props render the static
SVG on the server. Accessibility: the figure is named by title, described by summary and backed by a data table with every value (WCAG 1.1.1,
1.3.1). The plot is ONE tab stop: any arrow key moves between axes (Right and Down go clockwise), Home and End jump to the first and
last, and each axis is announced with all its values. Hovering or focusing an axis shows its spoke, a marker on each polygon and a
tooltip that stays while hovered and closes with Escape (1.4.13, 2.1.1). Axes are labelled with text. Polygons differ by colour, dash
and marker shape, and the legend toggles them (1.4.1). The draw-in is behind motion-safe:. The radar follows the container width,
the labels shorten and thin out, and the value list wraps under it (1.4.10); the plot stays left-to-right in right-to-left pages
while the card, list and table mirror, and digits follow the locale. Consumer duties: a title that asks the question, a summary with the main message, the scale in the description ("ratings, 1 to
5"), meaningful series names; a radar is hard to read precisely, use a BarChart to compare many values.
import { RadarChart } from "@nexera-ui/react";- 13
- examples
- 25
- props
- 5
- live controls
- 1
- platform
- 9
- 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 { RadarChart } from "@nexera-ui/react";
<RadarChart />Examples 12
The same examples as Storybook, rendered live. Open Code to copy one.
Single series
One series: the legend entry is static and the polygon is filled.
import { RadarChart } from "@nexera-ui/react";
<RadarChart series={[{ name: "Ayesha", data: [4.2, 4.6, 3.8, 3.4, 4.8, 4.4] }]} />;
Three series all filled
Three series: each polygon has its own colour, dash and marker shape; fill every polygon with fill="all".
import { RadarChart } from "@nexera-ui/react";
<RadarChart
fill="all"
series={[
{ name: "Ayesha", data: [4.2, 4.6, 3.8, 3.4, 4.8, 4.4] },
{ name: "Bilal", data: [3.1, 3.5, 4.4, 4.7, 3.2, 3.9], styleIndex: 1 },
{ name: "Team average", data: [3.6, 3.8, 3.9, 3.7, 3.9, 3.6], styleIndex: 7 },
]}
/>;
Missing values
A missing rating breaks the outline instead of being drawn as zero, and reads "No data" in the tooltip and the table.
import { RadarChart } from "@nexera-ui/react";
<RadarChart
series={[
{ name: "Ayesha", data: [4.2, null, 3.8, 3.4, null, 4.4] },
{ name: "Team average", data: [3.6, 3.8, 3.9, 3.7, 3.9, 3.6], styleIndex: 7 },
]}
/>;
Few axes
Three axes make a triangle; fewer than three still draw (a line for two, a point for one).
import { RadarChart } from "@nexera-ui/react";
<RadarChart
title="Pulse survey"
description="Average score, 1 to 5"
summary="Engagement is highest and workload lowest."
categories={["Engagement", "Workload", "Growth"]}
series={[{ name: "Q3 2026", data: [4.3, 2.9, 3.6] }]}
/>;
Many axes
Twelve axes: labels that would overlap are left out of the plot; the value list, the point labels and the table keep every axis.
import { RadarChart } from "@nexera-ui/react";
<RadarChart
title="Monthly engagement"
description="Average score, 1 to 5"
summary="Engagement dips in the summer months."
categories={["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]}
series={[
{ name: "2026", data: [4.1, 4.0, 4.3, 4.4, 4.1, 3.7, 3.4, 3.3, 3.9, 4.2, 4.4, 4.5] },
{
name: "2025",
data: [3.9, 3.9, 4.0, 4.1, 3.9, 3.6, 3.3, 3.2, 3.7, 4.0, 4.1, 4.3],
styleIndex: 7,
},
]}
/>;
Long labels
Long axis names are shortened in the plot to the room they have; the value list, the tooltip and the table keep them whole.
import { RadarChart } from "@nexera-ui/react";
<RadarChart
categories={[
"Cross-functional collaboration with product and design",
"Communication with customers and stakeholders",
"Delivery against the quarterly plan",
"Technical depth and code quality",
"Mentoring and growing teammates",
"Ownership of outcomes",
]}
/>;
Negative values
A scale that does not start at 0: negative values, with the rim and the centre set by the page.
import { RadarChart } from "@nexera-ui/react";
<RadarChart
title="Budget variance by team"
description="Percent against plan"
summary="Sales is 12 percent over plan, support 9 percent under."
categories={["Sales", "Engineering", "Support", "Operations", "Marketing"]}
series={[{ name: "Variance", data: [12, 3, -9, 0, 6] }]}
min={-15}
max={15}
valueFormat={{ signDisplay: "exceptZero" }}
/>;
Without value list
Without the value list the radar has the width; the values stay in the tooltip, the point labels and the table.
import { RadarChart } from "@nexera-ui/react";
<RadarChart isValueListHidden />;
Loading
Loading, empty and error are ChartStates inside the card; the header stays.
import { RadarChart } from "@nexera-ui/react";
<RadarChart state={{ status: "loading" }} />;
Empty
import { RadarChart } from "@nexera-ui/react";
<RadarChart
categories={[]}
series={[{ name: "Ayesha", data: [] }]}
state={{
status: "empty",
title: "No review yet",
description: "Reviews open in the last month of the quarter.",
}}
/>;
Error state
import { Button, RadarChart } from "@nexera-ui/react";
<RadarChart
state={{
status: "error",
title: "Couldn't load the review",
description: "Check your connection and try again.",
action: (
<Button variant="secondary" size="sm">
Try again
</Button>
),
}}
/>;
Right to left
Right-to-left page: the card, legend, value list and table mirror, the radar keeps its clockwise direction from 12 o'clock, digits follow the locale.
import { RadarChart } from "@nexera-ui/react";
<RadarChart
title="مراجعة المهارات: عائشة مقابل الفريق"
description="تقييمات المدير من ١ إلى ٥"
summary="تتفوق عائشة على متوسط الفريق في التواصل والتعاون."
categories={["القيادة", "التواصل", "التسليم", "التقنية", "التعاون", "المسؤولية"]}
series={[
{ name: "عائشة", data: [4.2, 4.6, 3.8, 3.4, 4.8, 4.4] },
{ name: "متوسط الفريق", data: [3.6, 3.8, 3.9, 3.7, 3.9, 3.6], styleIndex: 7 },
]}
table={{ categoryLabel: "المهارة", label: "عرض البيانات كجدول" }}
/>;
Props 25
Press "Try it" on a card to load that prop into the playground.
25 props shown
categories*Nexerareadonly string[]The names of the axes, one per spoke, in the order they run clockwise from 12 o'clock ("Leadership", "Communication"). The first value of every series belongs to the first axis. A long name is shortened in the plot to the room it has; the tooltip, the point labels, the value list and the table keep it whole. Radar charts read best with 3 to 8 axes.
series*Nexerareadonly ChartSeries[]The polygons. One series is a profile; two or more compare. Each series gets its own colour, dash and marker shape (WCAG 1.4.1); the legend toggles them.
minNexeranumberThe value at the centre. Set it below 0 for data with negative values; values below it are drawn at the centre.
maxNexeranumberThe value at the rim. Values above it are drawn at the rim; the tooltip and the table keep the real number.
ringsNexeranumberHow many grid rings the scale has, evenly spaced from the centre to the rim.
fillNexera"first" | "all" | "none"Which polygons are filled. Fills overlap, so a fill is never the only thing that tells series apart.
isValueListHiddenNexerabooleanHide the value list beside the radar. The values stay in the tooltip, the point labels and the table.
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.
heightNexeranumberHeight of the plot in px. The card grows with the header, KPI and legend around it.
isLegendHiddenNexerabooleanHide the legend. The series stay named in the tooltip, the point labels and the table.
plotLabelNexerastringAccessible name of the plot group. Translate it.
noDataLabelNexerastringText for a missing value in the tooltip and the table. Translate it.
hiddenSeriesNexerareadonly string[]Names of the hidden series (controlled). Pair it with onHiddenSeriesChange.
defaultHiddenSeriesNexerareadonly string[]Names of the series hidden at first (uncontrolled).
onHiddenSeriesChangeNexera(hidden: readonly string[]) => voidCalled with the names of the hidden series when the user toggles a legend entry.
* 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 · 1 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
- 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:.
<RadarChart 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.