Area chartFree
Overlaid, stacked or 100% areas with gaps kept and forecast tails.
npx shadcn@latest add https://beautifulcharts.dev/r/area-chart.jsonEngine: ·
Code
"use client";
import { useState } from "react";
import { AreaChart } from "@/components/beautiful-charts/themes/instrument/recharts/area-chart";
import type { ChartConfig, RangeValue } from "@/components/beautiful-charts/core/contracts";
const data = Array.from({ length: 36 }, (_, i) => ({
month: `M${i + 1}`,
desktop: 120 + Math.round(40 * Math.sin(i / 4)) + i * 3,
mobile: 80 + Math.round(30 * Math.cos(i / 5)) + i * 2,
}));
const config = {
desktop: { label: "Desktop", color: "var(--chart-1)", fill: "gradient" },
mobile: { label: "Mobile", color: "var(--chart-2)", fill: "gradient" },
} satisfies ChartConfig;
// A controlled brush: the range is yours, so a table or filter elsewhere can follow it.
export function VisitorsWithBrush() {
const [range, setRange] = useState<RangeValue>({ startIndex: 24, endIndex: 35 });
return (
<AreaChart
data={data}
xKey="month"
config={config}
title="Visitors"
stack="stacked"
brush={{ range, onRangeChange: setRange }}
/>
);
}
Props
xKey*
keyof TDatum & string
The category or time key on each row, e.g. "month".
grid
boolean
Draw grid lines behind the plot. On by default.
xAxis
AxisOptions
Category axis: hide it, format ticks, or add a label.
yAxis
AxisOptions
Value axis: hide it, format ticks, or add a label.
references
ReferenceLine[]
Target or threshold lines, fixed or computed from a series (average, median, max, min).
series
(keyof TDatum & string)[]
Series keys to draw, in order. Defaults to the keys in
config, then numeric keys in the data.stack
StackMode
"none" groups bars side by side and overlays areas. "stacked" stacks them. "percent" splits each row by its absolute total: positive parts stack up from zero, negative parts down, and the parts' sizes add to 100%.
orientation
"vertical" | "horizontal"
"vertical" (default) draws columns; "horizontal" draws bars along the value axis.
curve
Curve
Line and area interpolation. "monotone" (default) never overshoots the data.
radius
number
Bar corner radius in px. A series' own
radiusin config wins.barGap
number
Space between bars in one category, in px.
barCategoryGap
number
Share of each category left empty around its bars, 0–0.9.
maxBarSize
number
Widest a bar can get, in px.
showValues
boolean
Draw each value on its mark. Labels that don't fit are left out; the table and tooltip keep every value.
highlight
"max" | "none"
Emphasise the largest category and dim the rest. Ties, and rows with no positive total, emphasise nothing.
forecastFrom
number
Rows from this index on (inclusive) are a forecast: hatched bars, dashed lines and hatched areas.
polarity
"up" | "down"
Whether a rise is good ("up", the default) or bad ("down", e.g. costs or churn). Tints the delta by meaning.
brush
boolean | BrushOptions
An overview strip under the plot with a draggable window. Indexes in callbacks stay indexes into
data.readout
boolean
The big number in the header: the total for bars, the latest value for trends. Pass false to hide it (e.g. when a stat row says it better, or when a total means nothing, like a sum of percentages).
background
"none" | "rule" | "dots" | "grid" | "crosshair"
A quiet pattern behind the plot, drawn by the theme.
backgroundSlot
(plot: { x: number; y: number; width: number; height: number }) => ReactNode
Draw your own SVG behind the plot (any pattern or artwork). Receives the plot rectangle in px.
| Prop | Type | Description |
|---|---|---|
| xKey* | keyof TDatum & string | The category or time key on each row, e.g. "month". |
| grid | boolean | Draw grid lines behind the plot. On by default. |
| xAxis | AxisOptions | Category axis: hide it, format ticks, or add a label. |
| yAxis | AxisOptions | Value axis: hide it, format ticks, or add a label. |
| references | ReferenceLine[] | Target or threshold lines, fixed or computed from a series (average, median, max, min). |
| series | (keyof TDatum & string)[] | Series keys to draw, in order. Defaults to the keys in config, then numeric keys in the data. |
| stack | StackMode | "none" groups bars side by side and overlays areas. "stacked" stacks them. "percent" splits each row by its absolute total: positive parts stack up from zero, negative parts down, and the parts' sizes add to 100%. |
| orientation | "vertical" | "horizontal" | "vertical" (default) draws columns; "horizontal" draws bars along the value axis. |
| curve | Curve | Line and area interpolation. "monotone" (default) never overshoots the data. |
| radius | number | Bar corner radius in px. A series' own radius in config wins. |
| barGap | number | Space between bars in one category, in px. |
| barCategoryGap | number | Share of each category left empty around its bars, 0–0.9. |
| maxBarSize | number | Widest a bar can get, in px. |
| showValues | boolean | Draw each value on its mark. Labels that don't fit are left out; the table and tooltip keep every value. |
| highlight | "max" | "none" | Emphasise the largest category and dim the rest. Ties, and rows with no positive total, emphasise nothing. |
| forecastFrom | number | Rows from this index on (inclusive) are a forecast: hatched bars, dashed lines and hatched areas. |
| polarity | "up" | "down" | Whether a rise is good ("up", the default) or bad ("down", e.g. costs or churn). Tints the delta by meaning. |
| brush | boolean | BrushOptions | An overview strip under the plot with a draggable window. Indexes in callbacks stay indexes into data. |
| readout | boolean | The big number in the header: the total for bars, the latest value for trends. Pass false to hide it (e.g. when a stat row says it better, or when a total means nothing, like a sum of percentages). |
| background | "none" | "rule" | "dots" | "grid" | "crosshair" | A quiet pattern behind the plot, drawn by the theme. |
| backgroundSlot | (plot: { x: number; y: number; width: number; height: number }) => ReactNode | Draw your own SVG behind the plot (any pattern or artwork). Receives the plot rectangle in px. |
Props every chart shares (34): data, config, header, states, legend, tooltip, formatting, motion and selection
data*
TDatum[]
Your rows, as they are. Missing values (null, undefined, NaN) stay missing and are never drawn as zero.
locale
string
BCP 47 locale. Defaults to "en-US" so server and client render the same text.
timeZone
string
IANA time zone for dates. Defaults to "UTC" so server and client agree.
config
ChartConfig
Per-series label, colour, icon, format and style, keyed by series key. shadcn ChartConfig works as it is.
eyebrow
ReactNode
Small label above the title.
title
ReactNode
Card title. A string also names the chart for screen readers.
description
ReactNode
A line under the title.
takeaway
ReactNode | ((summary: string) => ReactNode) | false
The sentence under the title. Computed from the data by default; pass text, a function of the computed sentence, or false to hide it.
ariaDescription
string
Accessible summary for screen readers. Computed from the data by default.
motion
MotionPreference
"full" (default), "subtle" or "off". Reduced-motion settings always win.
motionOptions
MotionOptions
When the entrance plays.
sound
boolean
Sound cues on hover, scrub and select. Plays only if the visitor has also turned sound on for the page.
density
Density
"comfortable" (default) or "compact" for dashboards.
legend
LegendOptions | false
Legend position, alignment, shape and click action, or false to hide it.
tooltip
TooltipOptions<TDatum> | false
Tooltip position, indicator, cursor and custom content, or false to turn it off.
valueFormatter
(value: number) => string
Values formatted for display. Series formatters in config win.
loading
boolean
Show the loading state. Over existing data, the old marks stay dimmed instead of vanishing.
error
string | null
An error message. Shows the error state in place of the plot.
emptyState
ReactNode
Shown instead of the plot when there is no data.
loadingState
ReactNode
Shown while
loadingis true and there is no data yet.errorState
ReactNode
Shown when
erroris set.selected
number | null
Controlled and uncontrolled interaction state. Point selection (
selected) pins one row by its index indata. Series selection (selectedSeries) picks one series and dims the others. They are separate: picking a row doesn't pick a series.defaultSelected
number | null
Initial selected row when uncontrolled.
selectedSeries
string | null
Controlled series selection: this series stays lit and the others dim.
defaultSelectedSeries
string | null
Initial series selection when uncontrolled.
hidden
string[]
Controlled hidden series keys.
defaultHidden
string[]
Series hidden at first when uncontrolled.
activeIndex
number | null
Controlled hover or focus index, for syncing several charts on one cursor.
palette
"theme" | "shadcn"
Series colours: "theme" (default) uses the theme's designed palette; "shadcn" uses your --chart-1..5. --bc-series-N always wins. You can also opt a whole section in with the class bc-use-shadcn-colors.
table
boolean
Show the "Show data table" disclosure. On by default.
stats
ChartStat[]
A row of figures under the title, for dashboard cards and blocks.
footer
ReactNode
A line or action at the bottom of the card, e.g. a source note or a link.
className
string
Classes on the card, for spacing and layout.
height
number
Height of the plot area in px. The frame sizes around it.
| Prop | Type | Description |
|---|---|---|
| data* | TDatum[] | Your rows, as they are. Missing values (null, undefined, NaN) stay missing and are never drawn as zero. |
| locale | string | BCP 47 locale. Defaults to "en-US" so server and client render the same text. |
| timeZone | string | IANA time zone for dates. Defaults to "UTC" so server and client agree. |
| config | ChartConfig | Per-series label, colour, icon, format and style, keyed by series key. shadcn ChartConfig works as it is. |
| eyebrow | ReactNode | Small label above the title. |
| title | ReactNode | Card title. A string also names the chart for screen readers. |
| description | ReactNode | A line under the title. |
| takeaway | ReactNode | ((summary: string) => ReactNode) | false | The sentence under the title. Computed from the data by default; pass text, a function of the computed sentence, or false to hide it. |
| ariaDescription | string | Accessible summary for screen readers. Computed from the data by default. |
| motion | MotionPreference | "full" (default), "subtle" or "off". Reduced-motion settings always win. |
| motionOptions | MotionOptions | When the entrance plays. |
| sound | boolean | Sound cues on hover, scrub and select. Plays only if the visitor has also turned sound on for the page. |
| density | Density | "comfortable" (default) or "compact" for dashboards. |
| legend | LegendOptions | false | Legend position, alignment, shape and click action, or false to hide it. |
| tooltip | TooltipOptions<TDatum> | false | Tooltip position, indicator, cursor and custom content, or false to turn it off. |
| valueFormatter | (value: number) => string | Values formatted for display. Series formatters in config win. |
| loading | boolean | Show the loading state. Over existing data, the old marks stay dimmed instead of vanishing. |
| error | string | null | An error message. Shows the error state in place of the plot. |
| emptyState | ReactNode | Shown instead of the plot when there is no data. |
| loadingState | ReactNode | Shown while loading is true and there is no data yet. |
| errorState | ReactNode | Shown when error is set. |
| selected | number | null | Controlled and uncontrolled interaction state. Point selection (selected) pins one row by its index in data. Series selection (selectedSeries) picks one series and dims the others. They are separate: picking a row doesn't pick a series. |
| defaultSelected | number | null | Initial selected row when uncontrolled. |
| selectedSeries | string | null | Controlled series selection: this series stays lit and the others dim. |
| defaultSelectedSeries | string | null | Initial series selection when uncontrolled. |
| defaultHidden | string[] | Series hidden at first when uncontrolled. |
| activeIndex | number | null | Controlled hover or focus index, for syncing several charts on one cursor. |
| palette | "theme" | "shadcn" | Series colours: "theme" (default) uses the theme's designed palette; "shadcn" uses your --chart-1..5. --bc-series-N always wins. You can also opt a whole section in with the class bc-use-shadcn-colors. |
| table | boolean | Show the "Show data table" disclosure. On by default. |
| stats | ChartStat[] | A row of figures under the title, for dashboard cards and blocks. |
| footer | ReactNode | A line or action at the bottom of the card, e.g. a source note or a link. |
| className | string | Classes on the card, for spacing and layout. |
| height | number | Height of the plot area in px. The frame sizes around it. |
Events (5)
onSelectedChange
(selection: Selection<TDatum> | null) => void
Called when a row is selected or cleared, by pointer, keyboard or the data table.
onSelectedSeriesChange
(key: string | null) => void
Called when the selected series changes (legend "select" action, or a click on a series).
onHiddenChange
(hidden: string[]) => void
Called when the legend hides or shows a series.
onActiveChange
(index: number | null) => void
Called as the hovered or focused row changes, or null when it leaves.
onReady
(chart: EChartsType) => void
Called once with the ECharts instance, e.g. to add event listeners.
| Prop | Type | Description |
|---|---|---|
| onSelectedChange | (selection: Selection<TDatum> | null) => void | Called when a row is selected or cleared, by pointer, keyboard or the data table. |
| onSelectedSeriesChange | (key: string | null) => void | Called when the selected series changes (legend "select" action, or a click on a series). |
| onHiddenChange | (hidden: string[]) => void | Called when the legend hides or shows a series. |
| onActiveChange | (index: number | null) => void | Called as the hovered or focused row changes, or null when it leaves. |
| onReady | (chart: EChartsType) => void | Called once with the ECharts instance, e.g. to add event listeners. |
Recharts build only (1)
children
ReactNode
Recharts children render inside the chart: reference areas, custom labels, anything Recharts accepts.
| Prop | Type | Description |
|---|---|---|
| children | ReactNode | Recharts children render inside the chart: reference areas, custom labels, anything Recharts accepts. |
Apache ECharts build only (2)
renderer
EChartsRenderer
"canvas" (default, best for large data) or "svg".
option
OptionOverride
Deep-merged over the generated ECharts option (plain objects merge; arrays and class instances replace), or a function that receives the generated option and returns the final one. See the chart docs.
| Prop | Type | Description |
|---|---|---|
| renderer | EChartsRenderer | "canvas" (default, best for large data) or "svg". |
| option | OptionOverride | Deep-merged over the generated ECharts option (plain objects merge; arrays and class instances replace), or a function that receives the generated option and returns the final one. See the chart docs. |
Accessibility, keyboard and motion
- Pointer
- Hover shows a crosshair and a tooltip with every series at that point; click pins it. Clicking a legend item hides or shows its series. An optional brush drags to choose a window.
- Keyboard
- Tab lands once on the plot. Left and Right move between points (the first press goes to the latest), Up and Down change series, Home and End jump to the ends, Enter or Space pins, Escape clears.
- Screen readers
- Every move is announced as a sentence, not coordinates. "Show data table" opens the numbers as a real table, and missing values stay empty, never zero.
- Motion
- Lines draw left to right, areas fill behind them, then the labels and callout fade in. The headline number rolls in. With reduced motion everything appears settled at once, and nothing depends on the motion to be read.