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.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<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.jsonOr, 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 belowratio-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 usescolor, the part beyond it extends inoverrunColor, 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
| Prop | Type | Default | Description |
|---|---|---|---|
data | ChartDataPoint[] | — | 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) |
height | number | 240 | SVG height (px, including the label strip at the bottom) |
color | string | currentColor | Line/bar color (any CSS color) |
duration | number | 1.2 | Duration of the line/area stroke growth (seconds) |
stagger | number | 0.08 | Stagger interval for bars and data points (seconds) |
delay | number | 0 | Delay before the reveal starts (seconds) |
showGrid | boolean | true | Whether to show horizontal grid lines |
showLabels | boolean | true | Whether to show X axis labels |
showDots | boolean | true | Whether lines/areas show dots at the data points |
showValues | boolean | false | Whether to show values on the data points/bars |
strokeWidth | number | 2 | Line stroke width (px) |
once | boolean | true | Play only the first time the element enters the viewport |
target | number | — | Shared target: denominator for ratio-bars and target line for target-overrun (a data point's own target wins) |
overrunColor | string | "#f43f5e" | Accent color for the part of target-overrun beyond the target |
colors | string[] | — | Segment colors for composition-strip (applied in order; without it, color at stepped opacity) |
className | string | — | Class appended to the outermost container |
ChartDataPoint
| Field | Type | Description |
|---|---|---|
label | string | X axis label (for example a month or a category name) |
value | number | The value; bars grow from the baseline, lines/areas position themselves by it |
target | number | Optional 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, withtransform-box: fill-boxplustransform-originmaking positive values expand from the bottom and negative values from the top; lines and areas are drawn with Motion'spathLengthfrom 0 to 1, with the area fill fading in alongside - Viewport trigger:
useInViewdetects entering the viewport before playing, andoncecontrols 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 withdisconnecton 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 tocolorfor 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
staggerChildrenat the container level - Comparison styles: expand from the left via
scaleX, staggered bystagger; thetarget-overrunoverrun 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-overrundraws vertical grid lines instead), and negative values are treated as 0
Accessibility
- The SVG is marked
role="img"with anaria-label(a summary of "label: value" for each data point; comparison styles add the share or "value / target (percent)"), plus ansr-onlytext 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
Pricing Table
A pricing table with a monthly/yearly segmented switch; prices spring-tween on switch, the selected pill slides, the featured plan scales up and is highlighted, and yearly shows a discount badge.
Activity Feed
A live list that inserts items automatically — new events push in from the top and existing rows reflow smoothly with FLIP — with timeline and relative-time support.