Sparkline
- Stable
- WCAG 2.2 evidence
- RTL
A tiny inline trend graphic for a slot like the sparkline of
MetricCard: a line over the data, the area under it at 12 % and a dot at the end. Data driven: data in, SVG out. Presentational:
no hooks and no "use client", so it renders in React Server Components from props; it has no tooltip, no focus and no motion. Accessibility: the SVG is an image (role="img") that needs a text alternative (aria-label or aria-labelledby), because a
sparkline has no axes and no values to read; or decorative (aria-hidden) when the text beside it already says the same
(WCAG 1.1.1, 1.4.1). Direction is never colour alone: the shape of the line shows it, the end marker shows where it ends, and the
colour only tones it (brand for rising and volatile, danger for falling). The line is at least 3:1 against the card (1.4.11). The
time axis stays left-to-right in right-to-left pages (1.3.2). Consumer duties: write the label with the direction and the range ("Payroll over the last 12 months, rising 8 percent"); for exact
values or axes use a LineChart.
import { Sparkline } from "@nexera-ui/react";- 12
- examples
- 10
- props
- 4
- live controls
- 1
- platform
- 4
- WCAG criteria
- 2
- blocks use 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 { Sparkline } from "@nexera-ui/react";
<Sparkline />Examples 11
The same examples as Storybook, rendered live. Open Code to copy one.
Falling
Trend=Falling: the line and the dot turn status/danger/solid. The trend comes from the data when you do not pass one.
import { Sparkline } from "@nexera-ui/react";
const FALLING = [31, 30, 28, 29, 26, 24, 25, 22, 20, 18, 17, 15];
<Sparkline data={FALLING} aria-label="Time to hire over 12 months, falling 52 percent" />;
Volatile
Trend=Volatile: the line moves up and down and ends where it began.
import { Sparkline } from "@nexera-ui/react";
const VOLATILE = [12, 18, 9, 20, 11, 17, 8, 19, 10, 16, 13, 12];
<Sparkline data={VOLATILE} aria-label="Daily check-ins over 12 days, up and down around 13" />;
Flat
flat is not in Figma: the neutral grey of the chart palette, for data that hardly moves.
import { Sparkline } from "@nexera-ui/react";
<Sparkline data={[42, 42, 42, 42, 42, 42]} aria-label="Open roles stayed at 42 for six months" />;
Smooth without area
A smooth monotone curve, without the area.
import { Sparkline } from "@nexera-ui/react";
const RISING = [96, 99, 103, 101, 106, 110, 108, 114, 117, 121, 125, 128];
<Sparkline
data={RISING}
aria-label="Headcount over the last 12 months, rising 33 percent"
smooth
/>;
Missing values
Gaps (null) break the line and the area.
import { Sparkline } from "@nexera-ui/react";
<Sparkline
data={[96, 99, null, null, 106, 110, 108, null, 117, 121, 125, 128]}
aria-label="Headcount over 12 months, rising, with three months missing"
/>;
Single and empty
One value is a point; no value is a dashed line. The label should still say what is missing.
import { Sparkline } from "@nexera-ui/react";
export function SingleAndEmpty() {
return (
<div className="flex flex-wrap items-center gap-8">
<Sparkline data={[128]} aria-label="Headcount today: 128" />
<Sparkline data={[]} aria-label="No headcount history yet" />
</div>
);
}
Many points
365 daily points: the line stays one path; the label carries what matters.
import { Sparkline } from "@nexera-ui/react";
<Sparkline
data={Array.from({ length: 365 }, (_, i) => Math.round(100 + 40 * Math.sin(i / 40) + i / 10))}
aria-label="Daily active users over the last year, rising with a seasonal cycle"
/>;
Fills container
The size is yours: width and height set the drawing; className="w-full h-auto" fits it to its container and keeps the proportions.
import { Sparkline } from "@nexera-ui/react";
const RISING = [96, 99, 103, 101, 106, 110, 108, 114, 117, 121, 125, 128];
export function FillsContainer() {
return (
<div className="w-60 max-w-full rounded-lg border border-default p-3">
<Sparkline
data={RISING}
aria-label="Headcount over the last 12 months, rising 33 percent"
className="h-auto w-full"
/>
</div>
);
}
Decorative
Next to text that already says it all, the sparkline is decorative and hidden from assistive technology.
import { Sparkline } from "@nexera-ui/react";
const RISING = [96, 99, 103, 101, 106, 110, 108, 114, 117, 121, 125, 128];
export function Decorative() {
return (
<div className="flex items-center gap-4">
<span className="text-body-default text-primary">Headcount: 128, up 33 % in 12 months</span>
<Sparkline data={RISING} decorative />
</div>
);
}
In metric card
In the sparkline slot of a MetricCard, 90 x 36 px as in the Figma card.
import { MetricCard, Sparkline } from "@nexera-ui/react";
const RISING = [96, 99, 103, 101, 106, 110, 108, 114, 117, 121, 125, 128];
export function InMetricCard() {
return (
<div className="w-100 max-w-full">
<MetricCard
type="sparkline"
label="Monthly payroll"
value="Rs 29.0M"
delta="+4.2%"
caption="vs September"
sparkline={
<Sparkline
data={RISING}
width={90}
aria-label="Monthly payroll over the last 12 months, rising"
/>
}
/>
</div>
);
}
Right to left
Right-to-left page: the time axis keeps its left-to-right direction; the label is in the page language.
import { Sparkline } from "@nexera-ui/react";
const RISING = [96, 99, 103, 101, 106, 110, 108, 114, 117, 121, 125, 128];
<Sparkline data={RISING} aria-label="عدد الموظفين خلال ١٢ شهرًا، في ارتفاع بنسبة ٣٣ بالمئة" />;
Props 10
Press "Try it" on a card to load that prop into the playground.
10 props shown
aria-labelNexerastringWhat the sparkline shows, in words: "Payroll over the last 12 months, rising 8 percent". Say the direction and the range, because
the graphic has no axes. Translate it.
Text alternative used when aria-labelledby is not set.
aria-labelledbyNexerastringId of an element that names the sparkline; wins over aria-label.
Id of the visible element that says what the sparkline shows (the metric label and its caption).
decorativeNexerabooleanNot decorative: it is a named image.
The text next to the sparkline already says everything it shows (a delta badge "+8 %" and a caption "last 12 months"): hide the
drawing from assistive technology (aria-hidden). Only then is aria-label not needed.
data*Nexerareadonly (number | null)[]The values in time order, oldest first. null is a gap:
the line and the area break there. One value is drawn as a point, no value as a dashed line.
trendNexera"rising" | "falling" | "volatile" | "flat"The direction of the data and the tone of the graphic. The line itself shows the direction by its shape and the end
marker shows where it ends, so the colour is never the only cue (WCAG 1.4.1); say it in words in aria-label.
widthNexeranumberWidth of the drawing in px. The SVG keeps its proportions when CSS resizes it, so className="w-full h-auto" fits it
to a container.
heightNexeranumberHeight of the drawing in px.
smoothNexerabooleanDraw a smooth monotone curve instead of straight segments; the curve never leaves the data range.
areaNexerabooleanFill the area between the line and the bottom edge.
classNameNexerastringExtra classes, merged last so they win over the defaults.
* 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
3 direct · 1 supporting- 1.1.1Non-text ContentLevel A · tested directly
- 1.3.2Meaningful SequenceLevel A · supporting test
- 1.4.1Use of ColorLevel A · tested directly
- 4.1.2Name, Role, ValueLevel A · 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:.
<Sparkline 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.