KQ-1320 · CHART/MORPH
Chart Morph
A multi-series chart whose type is a shape the data takes, not a different drawing. Each series is one path rebuilt every frame from a few motion values — per point a flat top joined to the next by cubics that are either a notch to the floor or the curve between the points, plus a dot — so bars, line, area and dots are four settings of the same numbers, and a type change moves the points in a left-to-right sweep on glide: bars narrow and their notches rise into the curve, dots swell from the line or bars retract into them. The window, the y scale and each series' visibility glide too, gridlines riding the scale, and a cursor snaps to the nearest point on snap with a ring per series and a readout beside it. The type switch is a radio group, the legend toggle buttons, and the plot a slider: arrows step the cursor, Page keys three, Home and End to the ends, Escape clears it.
Payment volume
Fernworks Supply · $86.5K in Sep 2026
Last 12total
- Cardsavg $47.5K · +22.2%$569.7K
- Walletsavg $20.4K · +63.5%$244.5K
- Transfersavg $10.5K · −19.7%$125.5K
bar · last 12 months · cards, wallets, transfers
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/chart-morph
Props
- type / defaultType
- "bar" | "line" | "area" | "dot"
- default "bar"
- The chart type. Changing it morphs the same points into the new shape in a left-to-right sweep. Controlled or uncontrolled.
- onTypeChange
- (type: "bar" | "line" | "area" | "dot") => void
- default —
- Fires from the type switch with the new type.
- smooth
- number
- default 0.5
- Curve tension for the line and the area, 0 (straight segments) to 1 (monotone curves that never overshoot a reading); bars round their corners by it.
- points
- number
- default 12
- How many of the latest readings are shown, from 2 to all of them. A change glides the window, so points slide in from the left or out past it.
- series
- ChartMorphSeries[]
- default defaultChartMorphSeries
- The series: id, label, values (one per label, oldest first) and an optional colour (any CSS colour; defaults to the house pigments).
- labels
- string[]
- default defaultChartMorphLabels
- One label per reading, oldest first, such as "Sep 2026". The axis shows the first word; the readout and spoken text the whole label.
- hidden / defaultHidden
- string[]
- default []
- Series ids toggled off in the legend. A hidden series flattens to the floor and fades while the others re-dodge. Controlled or uncontrolled.
- onHiddenChange
- (hidden: string[]) => void
- default —
- Fires from the legend with the new hidden ids. The last visible series refuses to hide.
- onCursorChange
- (index: number | null) => void
- default —
- The point under the cursor changed (an index into labels), or the cursor left.
- wave
- number
- default 0.5
- How far a type change sweeps across the points, 0 (all at once) to 1 (a full left-to-right wave).
- format
- (value: number) => string
- default —
- How a reading prints on the axis, the legend, the readout and in spoken text. Defaults to compact currency in locale.
- locale
- string
- default "en-US"
- The locale for readings.
- currency
- string
- default "USD"
- The currency for readings.
- title
- string
- default "Volume"
- The chart's heading.
- subtitle
- string
- default —
- A quieter line under the heading, before the latest total.
- label
- string
- default —
- The chart's accessible name. Defaults to the title.
- status
- "ready" | "loading" | "error"
- default "ready"
- Whether the readings have arrived: loading shows a skeleton of bars, error a retry.
- onRetry
- () => void
- default —
- Try again was pressed after the readings failed to load.
- sound
- boolean
- default false
- Play a swish on a type change, pitched by type, and a tick when the cursor reaches a new point or a series is toggled.
- disabled
- boolean
- default false
- Shows the chart but refuses type, series and cursor changes.
- className
- string
- default —
- Classes for the outer panel.
| Prop | Type | Default | Description |
|---|---|---|---|
| type / defaultType | "bar" | "line" | "area" | "dot" | "bar" | The chart type. Changing it morphs the same points into the new shape in a left-to-right sweep. Controlled or uncontrolled. |
| onTypeChange | (type: "bar" | "line" | "area" | "dot") => void | — | Fires from the type switch with the new type. |
| smooth | number | 0.5 | Curve tension for the line and the area, 0 (straight segments) to 1 (monotone curves that never overshoot a reading); bars round their corners by it. |
| points | number | 12 | How many of the latest readings are shown, from 2 to all of them. A change glides the window, so points slide in from the left or out past it. |
| series | ChartMorphSeries[] | defaultChartMorphSeries | The series: id, label, values (one per label, oldest first) and an optional colour (any CSS colour; defaults to the house pigments). |
| labels | string[] | defaultChartMorphLabels | One label per reading, oldest first, such as "Sep 2026". The axis shows the first word; the readout and spoken text the whole label. |
| hidden / defaultHidden | string[] | [] | Series ids toggled off in the legend. A hidden series flattens to the floor and fades while the others re-dodge. Controlled or uncontrolled. |
| onHiddenChange | (hidden: string[]) => void | — | Fires from the legend with the new hidden ids. The last visible series refuses to hide. |
| onCursorChange | (index: number | null) => void | — | The point under the cursor changed (an index into labels), or the cursor left. |
| wave | number | 0.5 | How far a type change sweeps across the points, 0 (all at once) to 1 (a full left-to-right wave). |
| format | (value: number) => string | — | How a reading prints on the axis, the legend, the readout and in spoken text. Defaults to compact currency in locale. |
| locale | string | "en-US" | The locale for readings. |
| currency | string | "USD" | The currency for readings. |
| title | string | "Volume" | The chart's heading. |
| subtitle | string | — | A quieter line under the heading, before the latest total. |
| label | string | — | The chart's accessible name. Defaults to the title. |
| status | "ready" | "loading" | "error" | "ready" | Whether the readings have arrived: loading shows a skeleton of bars, error a retry. |
| onRetry | () => void | — | Try again was pressed after the readings failed to load. |
| sound | boolean | false | Play a swish on a type change, pitched by type, and a tick when the cursor reaches a new point or a series is toggled. |
| disabled | boolean | false | Shows the chart but refuses type, series and cursor changes. |
| className | string | — | Classes for the outer panel. |