Spec version v0.15.0

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 line and area variants; narrow rectangles for the bar variant. This is the only required visual element.
  • First-point marker (optional): a small filled circle at the leftmost data point, used in the with-endpoints variant to show where the series started.
  • Last-point marker (optional): a small filled circle at the rightmost (most recent) data point. Used in with-endpoints to 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-subtle to 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: reduce is 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-5 for negative or error direction
  • Weight: 2px at 60–120px width; 1.5px at 120–240px width

Fill — area variant

  • Colour: --force-color-chart-1 at 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-sm on 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 by prefers-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