Chart Utils
Shared helpers for building and styling your own charts.
Installation
pnpm dlx shadcn@latest add @paneui/chart-utilsUsage
Examples
Motion
useChartTransition, ChartNumber and ChartTooltip all become instant under reduced motion.
Accessibility
ChartNumber keeps the final value in a screen-reader-only span, ChartTooltip is a polite live region, and ChartDataTable renders an sr-only table mirror of a chart's data.
ChartNumber
Number that springs between values. Also accepts every prop of span.
- value*
- number
- Value to show.
- format= formatNumber
- (value: number) => string
- Formatter applied to every frame.
| Prop | Type | Default | Description |
|---|---|---|---|
| value* | number | — | Value to show. |
| format | (value: number) => string | formatNumber | Formatter applied to every frame. |
ChartTooltip
In-chart floating surface that follows a data point. Place it inside a positioned chart container; no portal. Also accepts every prop of motion.div.
- x*
- number
- Anchor x in px, relative to the chart container.
- y*
- number
- Anchor y in px.
- open*
- boolean
- Show or hide the tooltip.
- bounds*
- { width: number; height: number }
- Container size, used to keep the tooltip inside it.
- side= "top"
- "top" | "bottom" | "left" | "right"
- Preferred side.
- offset= 12
- number
- Gap from the anchor in px.
- avoidCollisions= true
- boolean
- Flip to the opposite side when the preferred side leaves the bounds.
| Prop | Type | Default | Description |
|---|---|---|---|
| x* | number | — | Anchor x in px, relative to the chart container. |
| y* | number | — | Anchor y in px. |
| open* | boolean | — | Show or hide the tooltip. |
| bounds* | { width: number; height: number } | — | Container size, used to keep the tooltip inside it. |
| side | "top" | "bottom" | "left" | "right" | "top" | Preferred side. |
| offset | number | 12 | Gap from the anchor in px. |
| avoidCollisions | boolean | true | Flip to the opposite side when the preferred side leaves the bounds. |
- data-side
- The side actually used after flipping.
| Data attribute | Description |
|---|---|
| data-side | The side actually used after flipping. |
ChartTooltipRow
Also accepts every prop of div.
- label*
- ReactNode
- Series name.
- value*
- ReactNode
- Formatted value, right-aligned.
- color
- string
- Swatch colour before the label.
| Prop | Type | Default | Description |
|---|---|---|---|
| label* | ReactNode | — | Series name. |
| value* | ReactNode | — | Formatted value, right-aligned. |
| color | string | — | Swatch colour before the label. |
ChartSwatch
Also accepts every prop of span.
- color*
- string
- CSS colour of the swatch.
| Prop | Type | Default | Description |
|---|---|---|---|
| color* | string | — | CSS colour of the swatch. |
ChartLegendItem
Legend entry, rendered as a button. Also accepts every prop of button.
- color*
- string
- Series colour.
- inactive
- boolean
- Dimmed with a hollow swatch (series toggled off).
- highlighted
- boolean
- Emphasised because the matching mark is hovered.
- value
- ReactNode
- Optional trailing value (share, count…).
| Prop | Type | Default | Description |
|---|---|---|---|
| color* | string | — | Series colour. |
| inactive | boolean | — | Dimmed with a hollow swatch (series toggled off). |
| highlighted | boolean | — | Emphasised because the matching mark is hovered. |
| value | ReactNode | — | Optional trailing value (share, count…). |
- data-inactive
- Present when
inactive. - data-highlighted
- Present when
highlighted.
| Data attribute | Description |
|---|---|
| data-inactive | Present when inactive. |
| data-highlighted | Present when highlighted. |
ChartDataTable
Screen-reader-only table mirror of a chart. Takes no other props.
- caption*
- string
- Table caption.
- columns*
- readonly string[]
- Column headers.
- rows*
- readonly (readonly ReactNode[])[]
- Rows; the first cell is the row header.
| Prop | Type | Default | Description |
|---|---|---|---|
| caption* | string | — | Table caption. |
| columns* | readonly string[] | — | Column headers. |
| rows* | readonly (readonly ReactNode[])[] | — | Rows; the first cell is the row header. |
chartColor
chartColor(index) returns the series colour, --chart-1…8 first (each falls back to a semantic token), then blends for indexes past eight. CHART_COLORS holds the base eight.
- index*
- number
- Series index.
| Prop | Type | Default | Description |
|---|---|---|---|
| index* | number | — | Series index. |
chartAlpha
chartAlpha(color, percent) mixes a colour toward transparent for fills.
- color*
- string
- Any CSS colour.
- percent*
- number
- Opacity, 0–100.
| Prop | Type | Default | Description |
|---|---|---|---|
| color* | string | — | Any CSS colour. |
| percent* | number | — | Opacity, 0–100. |
onFill
onFill(fill) returns a readable label colour for text drawn on that fill, white on dark fills, near-black on light ones (CSS relative colour). Set it as the inline fill and keep a fill-white class as the fallback for browsers without relative colour. Used by treemap, candlestick and funnel labels.
- fill*
- string
- The fill colour behind the label (any CSS colour or
var(--token)).
| Prop | Type | Default | Description |
|---|---|---|---|
| fill* | string | — | The fill colour behind the label (any CSS colour or var(--token)). |
scaleLinear
scaleLinear(domain, range) maps values to pixels; the result also has domain, range, invert(px) and ticks(count = 5).
- domain*
- readonly [number, number]
- Input extent.
- range*
- readonly [number, number]
- Output extent in px.
| Prop | Type | Default | Description |
|---|---|---|---|
| domain* | readonly [number, number] | — | Input extent. |
| range* | readonly [number, number] | — | Output extent in px. |
scaleBand
scaleBand(count, range, padding) returns the x of band i, plus bandwidth, step and indexAt(px).
- count*
- number
- Number of bands.
- range*
- readonly [number, number]
- Output extent in px.
- padding= 0.2
- number
- Share (0–1) of each step left empty.
| Prop | Type | Default | Description |
|---|---|---|---|
| count* | number | — | Number of bands. |
| range* | readonly [number, number] | — | Output extent in px. |
| padding | number | 0.2 | Share (0–1) of each step left empty. |
formatCompact / formatNumber / formatPercent
formatCompact(1284000) → 1.3M; formatNumber keeps up to 2 decimals; formatPercent(share, digits = 1) turns 0.42 into 42.0%. clamp(value, min, max) and seededRandom(seed), for deterministic demo data, are also exported.
useChartSize
const [ref, size] = useChartSize() observes an element's content box with ResizeObserver.
- initial= { width: 0, height: 0 }
- { width: number; height: number }
- Size before the first measure.
| Prop | Type | Default | Description |
|---|---|---|---|
| initial | { width: number; height: number } | { width: 0, height: 0 } | Size before the first measure. |
useChartTransition
Returns the house chart spring (CHART_SPRING), or { duration: 0 } under reduced motion.
- delay= 0
- number
- Delay in seconds.
| Prop | Type | Default | Description |
|---|---|---|---|
| delay | number | 0 | Delay in seconds. |
useActiveId
const [active, setActive] = useActiveId(value, defaultValue, onChange) holds the controlled or uncontrolled active id shared by the charts.
- controlled
- T | null | undefined
- Controlled value;
undefinedmeans uncontrolled. - defaultValue
- T | null | undefined
- Initial value when uncontrolled.
- onChange
- (id: T | null) => void
- Called on every change.
| Prop | Type | Default | Description |
|---|---|---|---|
| controlled | T | null | undefined | — | Controlled value; undefined means uncontrolled. |
| defaultValue | T | null | undefined | — | Initial value when uncontrolled. |
| onChange | (id: T | null) => void | — | Called on every change. |