Data Display

Animated Charts

Data-driven SVG charts that grow as they reveal — bars grow up from the baseline, lines and areas draw themselves along their stroke — triggered when they enter the viewport.

Bring this into your project

Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.

npx webberui@latest add animated-charts.en

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

1.2
2
Active edited usageDefault props
<AnimatedChart/>

The complete example includes the preview layout and data. Install the component first, then paste this file into your project.

Installation

npx webberui@latest add https://webberui.com/r/animated-charts.en.json

Or, once registries are configured in components.json, install it as @webberui/animated-charts.

Usage

import { AnimatedChart } from "@/components/ui/animated-charts";

const data = [
  { label: "January", value: 320 },
  { label: "February", value: 480 },
  { label: "March", value: 410 },
  { label: "April", value: 640 },
];

<AnimatedChart data={data} variant="line" />

Switching variant on the same data gives you all three styles — line, bar, or area:

<AnimatedChart data={data} variant="bar" />
<AnimatedChart data={data} variant="area" />

Custom colors (any CSS color; the default follows the text color and adapts to light and dark automatically):

<AnimatedChart data={data} variant="area" color="#6366f1" showValues />

Comparison styles

Beyond trend charts, variant also offers three comparison styles, laid out horizontally for showing shares and attainment:

  • composition-strip: a 100% stacked band — each segment's width is that item's share of the total, with a legend listing percentages below
  • ratio-bars: one track per item, filled to value ÷ target (without a target the max value is the denominator; capped at 100%)
  • target-overrun: the part up to the target uses color, the part beyond it extends in overrunColor, and a target tick is drawn
const channels = [
  { label: "Website", value: 128, target: 120 },
  { label: "Stores", value: 86, target: 100 },
  { label: "Group buy", value: 32, target: 25 },
];

<AnimatedChart data={channels} variant="composition-strip" height={112} />
<AnimatedChart data={channels} variant="ratio-bars" />
<AnimatedChart data={channels} variant="target-overrun" overrunColor="#f43f5e" />

Targets can be set per data point with target, or shared across all items with the target prop (a data point's own value wins). composition-strip tells segments apart with color at stepped opacity by default; pass a colors array for distinct colors.

The chart width fills the container automatically (measured internally with a ResizeObserver), and the height is controlled by height.

Props

AnimatedChart

PropTypeDefaultDescription
dataChartDataPoint[]—The chart data, laid out along the X axis in order
variant"line" | "bar" | "area" | "composition-strip" | "ratio-bars" | "target-overrun""line"Chart style (the last three are comparison styles)
heightnumber240SVG height (px, including the label strip at the bottom)
colorstringcurrentColorLine/bar color (any CSS color)
durationnumber1.2Duration of the line/area stroke growth (seconds)
staggernumber0.08Stagger interval for bars and data points (seconds)
delaynumber0Delay before the reveal starts (seconds)
showGridbooleantrueWhether to show horizontal grid lines
showLabelsbooleantrueWhether to show X axis labels
showDotsbooleantrueWhether lines/areas show dots at the data points
showValuesbooleanfalseWhether to show values on the data points/bars
strokeWidthnumber2Line stroke width (px)
oncebooleantruePlay only the first time the element enters the viewport
targetnumber—Shared target: denominator for ratio-bars and target line for target-overrun (a data point's own target wins)
overrunColorstring"#f43f5e"Accent color for the part of target-overrun beyond the target
colorsstring[]—Segment colors for composition-strip (applied in order; without it, color at stepped opacity)
classNamestring—Class appended to the outermost container

ChartDataPoint

FieldTypeDescription
labelstringX axis label (for example a month or a category name)
valuenumberThe value; bars grow from the baseline, lines/areas position themselves by it
targetnumberOptional target for this item (used by ratio-bars / target-overrun)

How it works

  • Growth reveal: bars grow up from the baseline (the position of value 0) via scaleY, with transform-box: fill-box plus transform-origin making positive values expand from the bottom and negative values from the top; lines and areas are drawn with Motion's pathLength from 0 to 1, with the area fill fading in alongside
  • Viewport trigger: useInView detects entering the viewport before playing, and once controls whether it plays only once
  • Responsive: the container width is measured internally with a ResizeObserver, and the SVG is drawn in pixel coordinates (not a scaled viewBox), so strokes and dots never distort at any width; the Observer is cleaned up with disconnect on unmount
  • Value range: the range always includes 0 as the bar baseline and supports negative values; when every value is identical it falls back to a safe ratio to avoid dividing by zero
  • Color: the default is currentColor, following the container's text color, so neutral colors and light/dark mode adapt automatically; pass any CSS color to color for an accent. Grid lines and labels stay a fixed understated neutral and do not change with the series color
  • Stagger: bars and data points reveal one after another via staggerChildren at the container level
  • Comparison styles: expand from the left via scaleX, staggered by stagger; the target-overrun overrun segment extends only after the base has grown, so the "over target" part appears last. Comparison styles draw no X axis labels or horizontal grid lines (target-overrun draws vertical grid lines instead), and negative values are treated as 0

Accessibility

  • The SVG is marked role="img" with an aria-label (a summary of "label: value" for each data point; comparison styles add the share or "value / target (percent)"), plus an sr-only text summary for assistive technology to announce
  • Grid lines, bars, paths, dots, value labels, and comparison segments and legends are all decorative and marked aria-hidden
  • When the user has "reduce motion" enabled at the system level, the chart shows its final state directly (bars at full height, paths complete, dots in place, comparison segments fully expanded) with no growth animation, and the DOM structure matches SSR