Spec version v0.15.0

Area chart

Purpose

An Area chart shows how a value accumulates over time, with the region beneath the line filled to emphasise volume. Use it when the cumulative quantity is the takeaway, or when several series stacked together sum to a meaningful total. Do NOT use an Area chart when the trajectory of the line is the primary read and the volume under it is irrelevant — use a Line chart instead. Do NOT use an Area chart with a stacked layout when any series contains negative values — negative numbers make the shared baseline jump and the composition unreadable.

Anatomy

An Area chart is composed of:

  • Title (required at md and lg): Headline label above the chart. Wraps to two lines; truncates with ellipsis beyond that. Optional at sm.
  • Subtitle (optional): One line of context under the title. Does not wrap.
  • Headline metric (optional): A KPI tile in the chart header — one summary number alongside the area. Number is the takeaway; the area shows the journey.
  • Action menu (optional): Per-widget controls — export, refresh, filter — pinned to the top-right corner.
  • Y axis: Numeric values. Always begins at zero. Unlike the Line chart, there is no exception — a floating baseline misrepresents the filled volume.
  • X axis: Time or continuous interval. Tick labels follow the Force UI date formatting rules and respond to the xFormat override.
  • Gridlines: Horizontal only by default, anchored to y-tick positions.
  • Area marks: A filled region per series. In the single variant, one region bounded above by an outline stroke and below by zero. In the stacked variant, each region is bounded above by its outline stroke and below by the previous series' top boundary.
  • Outline stroke: The line along the top boundary of each filled area. Visually distinct from the fill; carries series color at full opacity. In the stacked variant with three or more series, each series also uses a distinct stroke dash pattern (see Accessibility) so bands are distinguishable by shape as well as color.
  • Crosshair: A 1px vertical line that tracks the pointer along the x axis, anchoring the tooltip content to the nearest x value.
  • Tooltip: Appears on hover or keyboard focus. Shows the x label, then one row per visible series — a color swatch, the series name, and the formatted y value. In the stacked variant, a cumulative total row is appended at the bottom.
  • Legend: A row of color swatches with series labels, always positioned below the chart. Required whenever more than one series is shown at md or lg density.
  • Reference line (optional): A dashed horizontal threshold or average overlay. 1px dashed 2px 2px, --force-color-border-muted. Label right-aligned to the plot edge.
  • Empty, loading, error, and no-permission overlays: Replace the plot area when data is unavailable. Title and header always remain visible.

When to use

Use an Area chart when:

  • The reader is following a value's cumulative volume across time, or how several series sum to a total.
  • The x axis is continuous: a date range, a timestamp sequence, a build counter, a sprint cadence.
  • At least two data points exist per series so a shape can be drawn.
  • No more than five series are stacked (stacked variant), or no more than seven for the single variant.

Do NOT use an Area chart when:

  • The trajectory of the line is the primary question and volume is irrelevant — use a Line chart.
  • Negative values are present in a stacked layout — stacked areas cannot represent negatives. Use a Line chart or a grouped Bar chart instead.
  • The reader needs to read individual series values precisely — stacked areas make per-series values harder to compare than a Line chart.
  • The x axis is categorical (products, regions, teams) — use a Bar chart.
  • Only one data point exists — use a KPI tile.
  • The widget is rendered below 320px wide — use the Sparkline variant or a KPI tile.

Data requirements

Requirement Constraint Behavior at the limit or when violated
Required fields x (time or continuous), y (numeric, non-negative when stacked) If either is missing, render the Empty state with an explanation.
Accepted x types ISO datetime, epoch ms, or numeric ordinal Strings are not accepted. Pass categorical x to Bar chart instead.
Accepted y types Number for single. Non-negative number for stacked. Nulls are skipped; the area breaks across the gap with reduced opacity. Nulls are never silently zeroed — a zero would change the visual baseline.
Minimum data points 2 per series Fewer than 2 falls back to a KPI tile with the single value passed through.
Maximum data points 1 000 per series (SVG mode), 10 000 (canvas mode) Above the limit the chart downsamples and shows a banner explaining the reduced resolution.
Series count limit 5 for stacked, 7 for single and forecast Above the limit, group remaining series into "Other" and provide a "view all" link to the underlying table.
Negative values in stacked Not allowed A stacked payload containing negatives renders the Error state with a note redirecting to the Line chart.
Sort order Chart sorts x ascending regardless of input order The component cannot rely on the caller to pre-sort.
Aggregation No client-side aggregation. Caller provides values at the desired interval. If the interval is too dense for the rendered width, the chart downsamples and labels the new interval.

Configuration

Prop Type Default Purpose
CONTENT
title string required Headline label above the chart. Wraps to two lines, then truncates with ellipsis.
subtitle string undefined Optional one-line context under the title. Does not wrap.
headlineMetric { value, label, delta } undefined Optional KPI rendered in the chart header.
DATA
data Array<{x, y, series?}> required The data payload. Schema defined in Data requirements above.
groupBy string undefined Optional field name to split data into series. Also determines stack order in the stacked variant.
referenceLines Array<{ value, label, style? }> [] Horizontal threshold or comparison lines overlaid on the plot area.
xFormat string 'auto' Custom date or numeric format for x-axis tick labels. Defaults to the Force UI date formatting rules.
yFormat string 'auto' Custom number format for y values and tooltip. Supports: 'currency', 'percent', 'abbreviated', 'raw'.
VISUAL
variant 'single' | 'stacked' | 'forecast' | 'sparkline' 'single' Approved variants documented in the Variants section.
colorMapping Record<series, token> system Overrides the automatic categorical color mapping for this chart instance.
density 'sm' | 'md' | 'lg' 'md' Widget density. Affects type sizes, padding, tick density, and label rotation.
theme 'light' | 'dark' | 'auto' 'auto' Overrides the dashboard theme for this instance.
BEHAVIORAL
legend 'bottom' | 'none' 'bottom' when multi-series; 'none' when single series Controls legend visibility. Always positioned below the chart when shown.
tooltip boolean true When false, hover and focus produce no tooltip.
onMarkClick function undefined Optional drill-down callback. When set, the point on the outline stroke at the crosshair becomes focusable; clicking fires the handler with the data row.
exportable boolean true Whether the action menu exposes an Export option.
interactive boolean true Master switch. When false, the chart renders as a static image — no hover, tooltip, or keyboard behavior. Use for print and email contexts.
zoomable boolean false When true, scroll zooms the x axis, drag pans, and a reset affordance returns to the full range.
crossFilter boolean false When true, selecting a region updates other widgets on the dashboard that share the same data binding.

Variants

Four approved variants, selected via the variant prop.

Single

The most common configuration. One filled area per chart, bounded above by an outline stroke and below by the zero baseline. Fill uses the series' chart color at 40% opacity; outline stroke is the same color at full opacity. Use when the volume under a single time series is the takeaway — data ingest over time, CPU utilization, request rate.

Stacked

Multiple series stacked vertically on a shared zero baseline, each bounded by its own outline stroke. The fills sum to a total at every x point. Use when the composition of the total is the question — "how is this total distributed across components?" The stack order follows the groupBy field or, if unspecified, the order series appear in the data. The topmost series represents the total.

Legend items in this variant are ordered to match the stack from bottom to top. Clicking a legend item toggles its series; the remaining series reflow to fill the freed vertical space while maintaining the total shape.

Forecast

Divides each series at a labeled transition point. Observed data renders with full-opacity fill and solid outline stroke. Projected data renders at 30% opacity fill and 40% opacity outline stroke with a 4px 4px dash. The transition is marked with a short vertical dotted rule and a label ("Today" or "Forecast start"). Use for actual-vs-projected patterns — projected data ingest volume, forecast cloud spend.

This variant works with both single and stacked data: pass stacked data to data along with variant="forecast" and the forecast treatment applies to all series simultaneously.

Sparkline

A minimal area shape with no axes, no legend, no title, no tooltip, and no padding. The fill and outline stroke are shown at full opacity; the chart reduces to its silhouette. At sm density (< 320px), the chart enters a sparkline-like mode automatically — no axes, outline stroke only, fill at 30% opacity, tooltip on long press only. Use the sparkline variant explicitly for table cells, KPI tiles, or constrained widgets where only the trend shape is meaningful.

With headline metric

Not a separate variant — use variant="single" (or "stacked") and set headlineMetric. The KPI number is the primary takeaway; the area shows the cumulative path to that number.

With reference line

Not a separate variant — use referenceLines alongside any variant. Each reference line is a 1px dashed horizontal stroke in --force-color-border-muted with a right-aligned label.

States

The title and chart header always remain visible. Only the plot area changes.

Default (data loaded): Area fills and outline strokes are drawn. Null gaps in any series break the outline stroke and fill; the gap renders at reduced opacity (--force-opacity-subtle, 0.7) — never zeroed, because a silent zero would shift the visual baseline.

Loading: Data is being fetched. Render skeleton bars — a set of filled rectangles at varying heights inside the plot area, mimicking the filled chart shape — in --force-color-bg-muted. Do not use a spinner for charts taking longer than 200ms.

Empty: No data for the selected period. Show a brief explanation and, where applicable, a call to action. Use the EmptyState component inside the plot area.

Error: Data fetch failed. Show an explanation and a "Retry" button. Never silently fall back to the Empty state.

No permission: The viewer cannot access the underlying data. Replace the entire chart with a locked-state illustration and the message "You do not have access to this data." Do not expose any values or partial data.

Partial data: Some series or time intervals are missing. Render available data, break the affected fill at each gap, and add an inline banner below the chart explaining the missing period.

Single data point: Fewer than two points exist. Fall back to the KPI tile component with the single value passed through.

Stacked with negatives (error): A stacked variant payload containing negative y values cannot render correctly. Show an error overlay explaining the constraint ("Stacked areas require non-negative values") and suggest switching to a Line chart for data with negatives.

Interaction

Behavior Specification
Hover The crosshair tracks the pointer along the x axis. The nearest point on the outline stroke is highlighted with a filled marker at full opacity; all other series dim to --force-opacity-subtle (0.7).
Tooltip Floats approximately 12px from the cursor. Content anchored to the nearest x value: x label at top, one row per visible series (color swatch, series name, formatted value), and — in the stacked variant — a cumulative total row at the bottom. Opens on hover or keyboard focus; closes on pointer leave or Escape.
Touch Long press opens the tooltip. Tap elsewhere closes it.
Mark click No-op by default. When onMarkClick is set, the point on the outline stroke at the crosshair becomes focusable and clicking fires the handler with the corresponding data row.
Legend item click Toggles that series' visibility. In the stacked variant, remaining series reflow so their fills expand to fill the freed vertical space while preserving relative proportions.
Zoom and pan Off by default. When zoomable is true, scroll zooms the x axis, drag pans, and a reset affordance returns to the full range.
Cross-filter Off by default. When crossFilter is true, selecting a region updates other widgets sharing the same data binding.
Keyboard navigation Tab focuses the chart container. Left and Right arrows step through x values, opening the tooltip at each position. Enter fires onMarkClick if set. Escape closes the tooltip and returns focus to the chart container. Continued tabbing moves through legend items, then the action menu, then out of the chart.

Accessibility

Requirement Specification
Color contrast Every foreground and background pair meets WCAG 2.2 AA. Tokens in this spec resolve to compliant pairs. Custom colorMapping values must not break contrast against either the area fill or the outline stroke; violations are rejected at design review.
Color-blind safety Categorical palette passes Deuteranopia, Protanopia, Tritanopia, and Achromatopsia simulation. In the stacked variant with three or more series, outline strokes use distinct dash patterns per series so bands are differentiable by shape as well as color: series 1 solid, series 2 dashed 4px 4px, series 3 dotted 2px 2px, series 4 long-dashed 6px 2px, series 5 dash-dot 6px 2px 2px 2px. Color is never the only signal.
Screen reader The chart element has an accessible name (aria-label) derived from title. A summary sentence is exposed to assistive technology (e.g., "Cloud spend by provider, last 30 days. Total peaked at $112k on May 5."). A data table fallback is reachable via a "View as table" affordance on keyboard focus.
Keyboard reachability Every interaction is reachable via keyboard. Tab order: chart container → legend items (left to right) → action menu.
Focus indication A visible focus ring (--force-shadow-focus-ring + --force-color-border-focus) on the chart container, each legend item, and each focusable outline-stroke marker. Focus state is visually distinct from hover.
Reduced motion When prefers-reduced-motion: reduce is set, all draw-in animations, stacked-reflow transitions, and forecast-band animations are removed. Tooltip and focus states appear immediately.
Text scaling The component reflows at up to 200% text size without clipping or overlap. Axis labels collapse first, then tick density reduces, then the legend wraps.

Sizing and responsive behavior

Density Width range Use case What changes
Small (sm) < 320px Narrow inline widget No axes. Outline stroke only, fill at 30% opacity. Tooltip on long press only.
Medium (md) 320–599px Standard dashboard widget Compact axis labels. Numbers abbreviated. Legend wraps below. Tooltip shows one row per series (plus total for stacked).
Large (lg) ≥ 600px Full-width report Full axis labels. Multiple gridlines. Legend below. Tooltip shows extended metadata including the cumulative total for stacked.

Guidance

Choose the variant based on the question:

  • Single: "What is the cumulative volume of this metric over time?" — one filled area, volume is the read.
  • Stacked: "How is this total composed across components?" — multiple bands summing to a total, composition is the read.
  • Forecast: "Where is this volume heading?" — solid past, lighter projected, explicit transition label.
  • Sparkline: "What is the shape of this trend?" — no chrome, only the silhouette.

Common mistakes to avoid:

  • Do NOT truncate the y axis. A filled area with a floating baseline visually exaggerates the magnitude even more than a line chart does. Y axis always starts at zero.
  • Do NOT stack more than five series. Below five bands the lower areas flatten to the point where the reader cannot follow any single one. Group the rest into "Other."
  • Do NOT use stacked when any series contains negative values. The baseline jump makes the composition unreadable. Use a Line chart or grouped Bar chart for data with negatives.
  • Do NOT use a stacked area chart when the reader needs to compare individual series values precisely. Stacked areas are only easy to read for the bottom series and the total — intermediate series are hard to judge. Use a multi-series Line chart instead.
  • Do NOT use area: true on a Line chart as a substitute for the stacked variant. The Line chart area prop is a visual softener for a single series; it does not support stacking or the associated tooltip, legend, and reflow behaviors.

Token usage

Area fills

  • Fill color: --force-color-chart-1 through --force-color-chart-6 at 40% opacity
  • Forecast projected portion: fill at 30% opacity (from the already-reduced 40%, giving ~12% effective opacity)
  • Null gap segment: --force-opacity-subtle (0.7) applied to the gap fill

Outline stroke

  • Stroke color: --force-color-chart-1 through --force-color-chart-6 at full opacity
  • Stroke width: 2px at md and lg; 1.5px at sm
  • Forecast projected portion: 40% opacity, dash 4px 4px
  • Stacked series patterns (3+ series): series 1 solid, series 2 4px 4px, series 3 2px 2px, series 4 6px 2px, series 5 6px 2px 2px 2px
  • Null gap segment: --force-opacity-subtle (0.7), dash 4px 4px

Background and structure

  • Chart background: --force-color-bg-surface
  • Gridlines: --force-color-border-muted, 1px solid
  • Zero baseline: --force-color-border-default, 1px solid
  • Crosshair: --force-color-border-muted, 1px solid

Reference line

  • Stroke: --force-color-border-muted, 1px, dash 2px 2px
  • Label: --force-color-text-tertiary, --force-font-size-xs, right-aligned

Axis labels

  • Tick label color: --force-color-text-tertiary
  • Tick label size: --force-font-size-xs (12px)
  • Axis title color: --force-color-text-secondary
  • Axis title size: --force-font-size-xs

Tooltip

  • Background: --force-color-bg-inverse
  • Text: --force-color-text-on-inverse
  • Series swatch: 10px square using the series' chart color token (square to match the area fill shape)
  • Cursor offset: ~12px

Interaction and states

  • Dimmed (unfocused series): --force-opacity-subtle (0.7)
  • Focus ring: --force-shadow-focus-ring + --force-color-border-focus
  • Loading skeleton: --force-color-bg-muted

Motion

  • Draw-in on mount: --force-duration-normal (250ms), --force-easing-standard
  • Stacked series reflow on legend toggle: --force-duration-normal (250ms), --force-easing-standard
  • Data update transition: --force-duration-normal (250ms), --force-easing-standard
  • Tooltip open: --force-duration-fast (150ms), --force-easing-standard
  • Reduced motion override: all durations collapse to 0ms when prefers-reduced-motion: reduce

Related components

Component Relationship When to redirect
Line chart Same shape, unfilled. When the trajectory of the value is the primary question and the volume beneath it is not relevant.
Stacked bar Categorical sibling. When the x axis is discrete categories — products, regions, teams — and the reader is comparing composition per category.
Sparkline Inline variant of this chart. When the chart fits inside a table cell or KPI tile and only the trend shape is meaningful. Use via variant="sparkline".
KPI tile Single-value fallback. When only one data point exists or a single summary number is the takeaway.
Bar chart (grouped) For data with negatives or discrete categories. When any series contains negative values, or when the x axis is categorical.