Area chartFree

Overlaid, stacked or 100% areas with gaps kept and forecast tails.

npx shadcn@latest add https://beautifulcharts.dev/r/area-chart.json

Engine: ·

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 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 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.

  • 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.

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.

Recharts build only (1)
  • 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.

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.