M
MetricUI
Charts

AreaChart

A time-series area chart with gradient fills, stacking, dual Y-axis, comparison overlays, and reference lines.

import { AreaChart } from "metricui";

Use AreaChart to visualize time-series data with filled areas that emphasize volume and trends. It supports gradient fills, stacking, dual Y-axis, comparison overlays, reference lines, and threshold bands. For clean lines without area fills, use LineChart instead.

Basic Example

Revenue Over Time
<AreaChart
  data={[{
    id: "Revenue",
    data: [
      { x: "Jan", y: 42000 },
      { x: "Feb", y: 45000 },
      { x: "Mar", y: 48000 },
      // ...
    ],
  }]}
  title="Revenue Over Time"
  format={{ style: "currency" }}
/>

Stacked Areas

Pass multiple series and enable stacked to stack areas. Use stackMode="percent" to normalize to 100%.

Traffic Sources
<AreaChart
  data={trafficData}
  stacked
  title="Traffic Sources"
  format={{ style: "number", compact: true }}
/>

Comparison Overlay

Pass comparisonData to render a dashed overlay of a previous period. The comparison lines use 50% opacity so the current period stays prominent.

Revenue vs Last Year
Previous period
<AreaChart
  data={currentPeriod}
  comparisonData={previousPeriod}
  title="Revenue vs Last Year"
  format={{ style: "currency" }}
/>

Reference Lines & Thresholds

Add horizontal or vertical referenceLines for targets and benchmarks. Use thresholds to highlight Y-axis ranges (e.g., danger zones, target bands).

Revenue with Target
<AreaChart
  data={revenueData}
  title="Revenue with Target"
  format={{ style: "currency" }}
  referenceLines={[
    { axis: "y", value: 60000, label: "Target", color: "#EF4444", style: "dashed" },
  ]}
  thresholds={[
    { from: 40000, to: 55000, color: "#F59E0B", label: "Warning zone" },
  ]}
/>

Data States

Every component handles loading, empty, error, and stale states. Pass individual props or use the grouped state prop.

Loading

Error

Failed to load data

// Loading state
<AreaChart data={[]} title="Revenue" loading />

// Error state
<AreaChart data={[]} title="Revenue" error={{ message: "Failed to load" }} />

Props

PropTypeDescription
data*
{ id: string; data: { x: string | number; y: number | null }[] }[]

Array of data series. Each series has an id and array of {x, y} data points. y: null creates gaps.

index
string

Column key for the x-axis labels. Used with the unified flat-row data format. If omitted with categories, auto-inferred as the first string column.

categories
Category[]

Columns to plot as series. Accepts plain strings or CategoryConfig objects ({ key, label?, format?, color?, axis? }). If omitted with index, auto-inferred as all number columns.

simpleData
{ label: string; value: number | null }[]

Simple data format for single-series. Converted to full series internally. `data` takes precedence.

simpleDataId
string

Series name when using simpleData.

comparisonData
{ id: string; data: { x: string | number; y: number | null }[] }[]

Previous period data rendered as dashed overlay lines at 50% opacity. Same shape as `data`. Use for period-over-period comparison — e.g., this month vs last month. Series IDs must match `data` series IDs.

title
string

Chart card title.

subtitle
string

Chart card subtitle.

description
string | React.ReactNode

Description popover content.

footnote
string

Footnote below the chart.

action
React.ReactNode

Action slot in the top-right corner of the header.

format
FormatOption

Format for Y-axis values and tooltips.

height
number

Chart height in px. Dense mode defaults to 220.

curve
CurveType

Curve interpolation: "basis", "cardinal", "catmullRom", "linear", "monotoneX", "monotoneY", "natural", "step", "stepAfter", "stepBefore".

enablePoints
boolean

Show data points on the line.

enableArea
boolean

Show filled area under the line.

gradient
boolean

Use gradient fill instead of flat opacity.

areaOpacity
number

Area fill opacity when gradient is false.

stacked
boolean

Stack multiple series.

stackMode
"normal" | "percent"

Stack mode. "normal" stacks raw values, "percent" normalizes to 100%.

enableGridX
boolean

Show vertical grid lines.

enableGridY
boolean

Show horizontal grid lines.

referenceLines
ReferenceLine[]

Horizontal or vertical reference lines for targets, averages, or benchmarks. Each: `{ axis: 'x'|'y', value: number|string, label?: string, color?: string, style?: 'solid'|'dashed'|'dotted' }`. Rendered on top of the chart area.

thresholds
ThresholdBand[]

Colored horizontal range bands for danger/warning/safe zones. Each: `{ from: number, to: number, color: string, opacity?: number, label?: string }`. Rendered behind the chart area. Great for SLA targets, budget limits, or performance zones.

legend
boolean | LegendConfig

Legend with series toggle. `true` shows default legend. LegendConfig: `{ position?, orientation?, toggleable?, className? }`. Cmd/Ctrl+click to solo a series. ARIA keyboard accessible.

xAxisLabel
string

Label displayed along the X-axis. Use to clarify units or context (e.g., 'Month', 'Date'). Auto-hidden at narrow widths (<400px).

yAxisLabel
string

Label displayed along the Y-axis. Use to clarify units or context (e.g., 'Revenue ($)', 'Users'). Auto-hidden at narrow widths (<400px).

rightAxisSeries
string[]

Series IDs to plot on a separate right Y-axis. Use for dual-axis charts where series have different scales (e.g., revenue on left, percentage on right).

rightAxisFormat
FormatOption

Format for the right Y-axis values and tooltips. Typically different from the left axis (e.g., left='currency', right='percent').

rightAxisLabel
string

Label for the right Y-axis.

lineWidth
number

Line width in px.

lineStyle
"solid" | "dashed" | "dotted"

Line stroke style.

pointSize
number

Point radius in px.

pointColor
string | { from: string; modifiers?: any[] }

Point fill color. Default creates hollow ring effect. Use { from: "serieColor" } for solid.

pointBorderWidth
number

Point border width in px.

pointBorderColor
string

Point border color. Default: series color.

seriesStyles
Record<string, SeriesStyle>

Per-series visual overrides keyed by series ID. Override color, lineWidth, lineStyle ('solid'|'dashed'|'dotted'), pointSize, pointColor, pointBorderWidth for individual series. E.g., make one series dashed while others are solid.

colors
string[]

Series colors. Default: theme series palette (SERIES_COLORS).

onPointClick
(point: { id: string; value: number; label: string; seriesId: string; x: string | number; y: number }) => void

Click handler for data points.

dense
boolean

Compact layout — reduces margins and default height.

chartNullMode
ChartNullMode

How null/missing data points are handled: "gap", "zero", or "connect".

animate
boolean

Enable/disable chart animation. Falls back to config.animate.

variant
CardVariant

Card variant (supports custom strings). CSS-variable-driven via [data-variant]. Falls back to config.variant.

className
string

Additional CSS class names.

classNames
{ root?: string; header?: string; chart?: string; legend?: string }

Sub-element class name overrides.

id
string

HTML id attribute.

data-testid
string

Test id for testing frameworks.

loading
boolean

Loading state.

empty
EmptyState

Empty state configuration.

error
ErrorState

Error state configuration.

stale
StaleState

Stale data indicator.

crossFilter
boolean | { field: string }

Enable cross-filter signal on click. true uses the index field, { field } overrides. Emits selection via CrossFilterProvider — does NOT change chart appearance. Dev reads selection with useCrossFilter() and filters their own data.

tooltipHint
boolean | string

Show action hint at bottom of tooltip. true: auto ('Click to drill down' / 'Click to filter'). string: custom hint text. false: disable. Default: respects MetricConfig.tooltipHint (true).

drillDown
boolean | ((event: { indexValue: string; data: Record<string, unknown> }) => React.ReactNode)

Enable drill-down on click. `true` auto-generates a summary KPI row + filtered DataTable from the chart's source data. Pass a render function for full control over the panel content. Requires DrillDown.Root wrapper. When both drillDown and crossFilter are set, drillDown wins.

drillDownMode
DrillDownMode

Presentation mode for the drill-down panel. "slide-over" (default) slides from the right, full height. "modal" renders centered and compact.

exportable
ExportableConfig

Enable PNG/CSV/clipboard export. true: auto-exports source data as CSV. { data: rows[] }: exports custom rows. Charts auto-detect source data. Set globally via MetricProvider or per-component.

Data Shape

// Full series format
type Datum = { x: string | number; y: number | null };
type SeriesData = { id: string; data: Datum[] };

// Simple format (single series)
type SimpleData = { label: string; value: number | null }[];

Notes

  • Uses forwardRef.
  • Uses forwardRef — attach a ref to the root div.
  • X-axis ticks are automatically thinned based on container width.
  • Left Y-axis is hidden at container widths below 300px.
  • When using rightAxisSeries, right-axis data is internally normalized to the left scale and de-normalized for tooltips.
  • Comparison data renders as dashed lines at 50% opacity.
  • simpleData is converted to full series format internally; `data` takes precedence when non-empty.
  • crossFilter prop emits a selection signal on click — it does NOT change the chart's appearance. The dev reads the selection via useCrossFilter() and filters their own data.
  • drillDown={true} auto-generates a summary KPI row + filtered DataTable from the chart's source data. Pass a render function for custom panel content. Requires DrillDown.Root wrapper.
  • When both drillDown and crossFilter are set on the same component, drillDown wins.
  • All charts use CardShell internally. CardShell features (export, auto empty state, variant, dense, data states) work everywhere automatically.
  • exportable: true auto-exports the chart's source data as CSV. Charts auto-detect their data — no manual { data } override needed.
  • Auto empty state: when the chart has no data (exportData.length === 0), CardShell shows 'Nothing to show — try adjusting your filters' automatically. Override globally via MetricProvider.emptyState or per-component via the empty prop.

Playground

Experiment with every prop interactively. Adjust the controls on the right to see the component update in real time.

Live Preview

Revenue Over Time

Monthly recurring revenue

Code

<AreaChart
  data={[{ id: "Revenue", data: [...] }]}
  title="Revenue Over Time"
  subtitle="Monthly recurring revenue"
  format={{ style: "currency" }}
/>

Props

Adjust props to see the chart update in real time

Switch between sample datasets

Applied to Y-axis labels and tooltips

Line interpolation method

Stroke width in px

Stroke dash pattern

When set, stacking is implicit. 'percent' normalizes to 100%.