Sparkline
Purpose
A Sparkline shows the shape and direction of a small time series in a constrained space, without axes or labels. Its single question is: what is the recent trend of this value, at a glance?
A Sparkline is always nested inside a carrier — a table cell, KPI tile, or compact card. The carrier provides context (label, current value, period). The Sparkline provides shape. Neither is useful without the other.
Do NOT use a Sparkline when the widget has room for axes and labels — use a Line chart instead; adding chrome to a sparkline just makes a tiny, illegible line chart. Do NOT use a Sparkline when exact values matter — the shape is the message.
Anatomy
A Sparkline has no title, no subtitle, no axes, no gridlines, and no legend. Everything the reader needs to interpret the shape is supplied by the surrounding carrier.
- Plot area: a bounded region sized to fit its carrier. Typically 60–120px wide and 16–40px tall in table cells; up to 240px wide and 64px tall in KPI tiles or wide table columns. The sparkline fills this region edge to edge with no internal padding.
- Data marks: a stroke for
lineandareavariants; narrow rectangles for thebarvariant. This is the only required visual element. - First-point marker (optional): a small filled circle at the leftmost data point, used in the
with-endpointsvariant to show where the series started. - Last-point marker (optional): a small filled circle at the rightmost (most recent) data point. Used in
with-endpointsto show where the series ended. - Endpoint value labels (optional): short text labels beside the first and last markers (e.g., "180 ms → 270 ms"). Only at md density or wider.
- Baseline reference (optional): a faint horizontal line at a meaningful reference value — zero, a target, or the series average. Not a visible axis; rendered at
--force-opacity-subtleto avoid reading as an axis tick. - Implicit axes (omitted by design): there are no visible x-axis, y-axis, tick marks, or gridlines. The sparkline is defined by what it omits.
The Sparkline does not host a tooltip of its own. The tooltip belongs to the carrier and reveals on carrier hover or focus.
When to Use
Use a Sparkline when:
- The component must fit inside a table cell, KPI tile, or other dense carrier.
- Shape and direction are the takeaway — not precise values.
- The reader is scanning many rows and needs comparable trends at a glance.
- The series has between 5 and 60 points.
Do NOT use a Sparkline when:
- The widget has room for axes and labels. Use a Line chart — sparklines waste the available space.
- Exact values matter. Use a Line chart or an additional text column.
- The series has fewer than 5 points. Use a KPI tile.
- The series has more than 60 points competing for pixels. Use a Line chart with horizontal scroll.
- The data is categorical, not a time series. Use the Bar chart's mini/sparkline variant.
- Multiple series need to be compared inline. Use mini bar rows or a small-multiples grid.
Data Requirements
| Requirement | Constraint | Behaviour at the limit |
|---|---|---|
| Required fields | values (array of numbers). Optional x (array of datetimes for irregular spacing) |
Missing or empty values → carrier renders a "—" em dash in place of the sparkline |
| Accepted data types | Number arrays. ISO datetimes accepted when paired with x |
Strings are rejected. Mixed arrays → Error state |
| Minimum data points | 5 | Below 5 → carrier renders a single dot (if 1) or omits the sparkline; redirect to KPI tile |
| Maximum data points | 60 | Above 60 → silently downsample to 60; no banner needed |
| Series count | 1 | Multi-series sparklines are not supported in v1 — the pixels do not support legibility |
| Null / missing values | Line breaks across the gap. No interpolation, no zero substitution | Series with more than 25% nulls render a dimmed "low confidence" stroke and an asterisk on the carrier's latest value |
| Negative / zero values | Allowed. The sparkline auto-scales to the full data range | Warning: two sparklines in the same column are NOT directly comparable unless the carrier normalises their ranges |
| Sort order | Sorted x-ascending regardless of input order | — |
| Aggregation | None. Caller provides values at the desired interval | — |
Configuration
Content
| Prop | Type | Default | Purpose |
|---|---|---|---|
title |
string |
undefined |
Not used. The carrier's column header or label provides context. |
subtitle |
string? |
undefined |
Not used. |
Data
| Prop | Type | Default | Purpose |
|---|---|---|---|
data |
array |
required | Array of numbers or {x, y} objects. Schema defined in Data Requirements above. |
referenceLines |
object[]? |
[] |
Optional baseline reference. Each: {value, style}. Typically zero, a target, or the series average. Rendered at --force-opacity-subtle. |
Visual
| Prop | Type | Default | Purpose |
|---|---|---|---|
variant |
'line' | 'area' | 'bar' | 'with-endpoints' | 'in-kpi-tile' | 'in-table-row' |
'line' |
Approved variants documented in the Variants section. |
colorMapping |
object? |
system | Single colour override. Used to align sibling sparklines or encode positive versus negative direction. |
theme |
'light' | 'dark' | 'auto' |
'auto' |
Overrides the dashboard-level theme. |
Behavioural
| Prop | Type | Default | Purpose |
|---|---|---|---|
legend |
'none' |
'none' |
Always none. Sparklines never host legends. |
tooltip |
boolean |
true |
Hover or focus on the carrier reveals a tooltip with the latest value, the period covered, and the percentage change over the period. |
onMarkClick |
function? |
undefined |
If set, clicking the sparkline opens the full Line chart in a drawer. Rarely used. |
exportable |
boolean |
false |
Default false. Sparklines export with their carrier, not independently. |
Note: density is always 'sm'. The sparkline is sm by definition; the carrier controls the available width, not a density prop.
Variants
line (default)
A single smooth stroke through the values. Use as the default for any inline trend-shape use. The stroke weight is 2px at sm size (60–120px) and 1.5px at md (120–240px).
area
A filled region beneath the stroke. Use when emphasising cumulative volume over the period, or when the sparkline must read at very small sizes where a 2px stroke alone might disappear. Fill is the stroke colour at 15% opacity (matching the area: true behaviour of the Line chart). Use sparingly — filled sparklines carry more visual weight in dense tables.
bar
One narrow rectangle per data point, all at the same width. Use when the data represents bucketed counts where each period stands alone rather than connecting to the next (e.g., daily failed-build counts, weekly deployment frequency). Bars use --force-radius-sm on the top two corners only.
with-endpoints
A line sparkline plus a filled circle at the first data point (leftmost) and a filled circle at the last data point (rightmost). At md density, short text labels show both values (e.g., "180 → 270 ms"). An optional faint baseline may accompany this variant. Use when the start, the end, and the direction of travel are all part of the story.
in-table-row
The canonical placement context. A sparkline column in a multi-column table, paired with a label column on the left and a current-value column on the right. The carrier (the table row) provides the header label ("7-DAY LATENCY"), the sparkline provides trend shape, and the sibling column provides the precise current value. The sparkline does not need its own label or value — the table columns supply both.
Use the line or with-endpoints visual variant inside in-table-row. The bar variant is appropriate when the table column header describes counts.
in-kpi-tile
A sparkline tucked beneath the headline number of a KPI tile. The tile's number is the takeaway; the sparkline shows the journey. Rendered at the full width of the KPI tile body, typically 40–48px tall. Use the line or area visual variant here — the filled area provides stronger visual presence beneath a headline number.
Always pair with a percentage change badge (e.g., "+12%") above or beside the sparkline so the direction of the trend is explicitly labelled.
States
Default (happy path)
The sparkline renders its marks at full opacity with the series colour. In the with-endpoints variant, the last marker pulses once on load to draw the eye. No animation otherwise; sparklines do not animate into position.
Loading
Render a skeleton — a thin, rounded rectangle at the sparkline's position, the same dimensions as the plot area, in --force-color-bg-muted with an animated shimmer. Do NOT use a spinner — the skeleton communicates "loading" without diverting the eye from the carrier's other columns.
Empty
No data exists for the period. The sparkline area is replaced by an em dash ("—") in --force-color-text-secondary. The carrier's other columns remain fully rendered. Do NOT show a flat zero line in place of an absent sparkline — a flat line implies a real reading of zero.
Error
Data fetch failed. A small error indicator fills the sparkline area (a muted rounded rectangle with a "!" icon and the label "error"). The carrier's other data columns may show a "—" for the current value. Retry is available via the carrier's action menu, not inline in the sparkline cell.
No Permission
The viewer cannot see this series' data. The sparkline area shows a "—" em dash. The carrier renders other columns as normal — only the restricted series is blanked.
Partial Data (Low Confidence)
More than 25% of the series' values are null. Render the available stroke at --force-opacity-subtle (0.7) to signal reduced confidence. Place a small warning indicator near the last point. Append an asterisk to the current value in the carrier's value column ("275 ms*") so the low-confidence signal travels to the precise value as well.
Single Data Point
With only one value, a single dot is rendered at the horizontal midpoint of the plot area. The dot is positioned at the vertical midpoint. The carrier's value column shows the single value. No line is drawn. Below 5 points the caller should redirect to a KPI tile; this state covers the boundary case where 1 point arrives unexpectedly.
Interaction
Hover and Focus
Hovering the carrier (table row, KPI tile) or moving keyboard focus to the carrier reveals the tooltip. The sparkline itself is not a separate hover target at sm sizes — the interaction surface is the entire carrier row or tile.
Tooltip
Anchored to the carrier (not cursor-following). Shows:
- The series label (from the carrier's column header)
- The latest value with its unit
- The period covered (e.g., "Last 7 days")
- The percentage change over the period (e.g., "+50% vs prior week")
No per-point value breakdown at inline sizes. If onMarkClick is set and the carrier is clicked, the full Line chart opens in a drawer with per-point tooltips available there.
Click
No-op by default. If onMarkClick is set, clicking anywhere in the sparkline plot area (or pressing Enter on the focused carrier) opens the full Line chart in a drawer. The drawer shows the same data with proper axes, labels, and a crosshair.
Zoom, Pan, Cross-Filter
Not applicable. Sparklines are static; they do not zoom, pan, or participate in dashboard cross-filter.
Keyboard Navigation
Tab focuses the carrier (table row or KPI tile). The sparkline is not separately focusable. Screen reader users navigate the carrier; the sparkline contributes to the carrier's accessible name, not as a separate focus stop.
Accessibility
- Colour contrast: stroke and fill against the carrier background meet WCAG 2.2 AA. The sparkline never relies on a faint colour as the sole means of communication — the carrier column always provides the precise value.
- Colour-blind safety: strokes are single-colour by default. When positive/negative direction is encoded via colour (e.g., green up / red down), direction is reinforced by a directional arrow or delta badge next to the latest value in the carrier — colour alone is never the only signal.
- Screen reader pattern: the sparkline is not exposed as a graphical element to assistive technology. Instead, it contributes a text string to the carrier's accessible name:
"<series label>, <latest value>, <change over period>, trend <direction>". The shape is not described. A tooltip on the carrier remains accessible via focus. - Keyboard reachability: focus is on the carrier. The sparkline plot area is not a separate tab stop.
- Focus indication: the focus ring appears on the carrier (table row or KPI tile) using
--force-shadow-focus-ring. The sparkline cell does not receive its own focus ring. - Reduced motion: when
prefers-reduced-motion: reduceis set, no entry animation or pulse occurs. The updated shape appears immediately. - Text scaling: when the carrier reflows at up to 200% text size, the sparkline scales horizontally to maintain its proportions. It does not exceed 64px in height regardless of carrier scaling.
Sizing
| Width | Use case | What changes |
|---|---|---|
| 60–120px (sm) | Table cell, KPI tile, compact card | 2px stroke weight. No endpoint markers. No baseline. Tooltip only via carrier focus. |
| 120–240px (md) | Wide table column, dashboard tile | Optional first/last endpoint markers. Optional baseline reference. Tooltip via carrier. |
| > 240px | Not recommended | Beyond 240px the sparkline starts to feel like an under-labelled line chart. Switch to a Line chart with proper axes and labels. |
Height is determined by the carrier, not by the sparkline. Maximum supported height is 64px. Below 16px height, the sparkline renders only the line stroke; area fill and endpoint markers are suppressed.
Guidance
Do
- Always pair the sparkline with a current value in the carrier. A bare sparkline alone — shape with no number and no period — gives the reader no anchor. The value column answers "how much?"; the sparkline answers "which way?".
- Keep the sparkline to one series. Multiple coloured strokes in a 40px plot area are indistinguishable and undermine the table's scannability.
- Strip all chrome. No axes, no tick labels, no grid lines, no title. The carrier provides every textual element the reader needs. A sparkline with axis ticks is just a tiny, illegible line chart.
- When using colour to encode direction (up = positive, down = negative), always add a directional badge or arrow beside the value. Colour alone does not travel to colour-blind readers or printed output.
Don't
- Do NOT stretch a sparkline beyond 240px and call it a sparkline. Give the reader a proper Line chart.
- Do NOT show two sparklines in the same column and imply they are comparable when their Y scales differ. Either normalise the Y range at the carrier level or add a note that scales differ.
- Do NOT leave the sparkline area blank when data is missing. Show a "—" em dash so the reader knows the absence is intentional, not a rendering failure.
- Do NOT add a legend to a sparkline. It is single-series by definition. If you need a legend, the data has outgrown the sparkline format.
Token Usage
Stroke — line and area variants
- Colour:
--force-color-chart-1(default);--force-color-chart-5for negative or error direction - Weight: 2px at 60–120px width; 1.5px at 120–240px width
Fill — area variant
- Colour:
--force-color-chart-1at 15% opacity - Use
fill-opacity: 0.15(not an alpha in the colour value, to ensure dark mode tokens resolve correctly)
Bars — bar variant
- Fill:
--force-color-chart-1 - Gap between bars: 2px
- Border radius:
--force-radius-smon top-left and top-right corners only
Endpoint markers
- Fill:
--force-color-chart-1 - Size: 6px diameter circle
- Last-point marker pulse animation: single pulse over
--force-duration-moderate(300ms), suppressed byprefers-reduced-motion
Baseline reference
- Stroke:
--force-color-border-default - Opacity:
--force-opacity-subtle(0.7) - Weight: 1px, dashed
4px 2px
Endpoint value labels
- Font size:
--force-font-size-xs - Colour:
--force-color-text-secondary
Low-confidence stroke (partial data)
- Opacity:
--force-opacity-subtle(0.7) - Colour:
--force-color-chart-1(unchanged; opacity is the signal)
Loading skeleton
- Background:
--force-color-bg-muted - Border radius:
--force-radius-sm - Shimmer animation: standard skeleton shimmer pattern
Em dash placeholder (empty / no-permission)
- Text: "—"
- Colour:
--force-color-text-secondary - Font:
--force-font-size-sm
Error indicator
- Background:
--force-color-bg-muted - Icon colour:
--force-color-icon-destructive - Label:
--force-font-size-xs,--force-color-text-secondary
Related Components
| Component | Relationship | When to redirect |
|---|---|---|
| Line chart | Full-size sibling | When the widget has room for axes, labels, and a legend — use the Line chart and skip the sparkline |
| KPI tile | No-trend fallback | When fewer than 5 data points exist, or when only the latest value matters and trend shape adds no information |
| Bar chart (mini/sparkline variant) | Categorical inline alternative | When the data is bucketed counts or categorical values, not a connected time series |