Platform Blocks Charts
@platform-blocks/charts is a React Native + Web charting library (SVG via
react-native-svg, animations via react-native-reanimated) with 25 chart
components, a shared interaction engine (tooltips, crosshair, pan/zoom), and a
theme bridge for host design systems. Docs: https://platform-blocks.com
- Chart catalog + core APIs:
references/api.md
- Complete copy-paste examples:
references/patterns.md
Install
npm install @platform-blocks/charts react-native-svg react-native-reanimated
# Expo: npx expo install react-native-svg react-native-reanimated
Peer dependencies: react >= 18, react-native >= 0.73,
react-native-svg >= 13, react-native-reanimated >= 3.4
(react-dom optional, web only). Reanimated needs its Babel/worklets plugin
configured in the consuming app.
Theming: ChartThemeProvider + hostThemeBridge
Wrap the app (or any subtree) in ChartThemeProvider. Without it, charts use a
light default theme. To match the host app, pass hostThemeBridge — all fields
optional: textPrimary, textSecondary, background, grid,
accentPalette (string[]), fontFamily.
Real pattern from platform-blocks.com (bridging @platform-blocks/ui):
import { useTheme } from '@platform-blocks/ui';
import { ChartThemeProvider } from '@platform-blocks/charts';
// Categorical series palette — fixed hue order, assigned by slot, never cycled.
// Pinned as hex (not theme ramp indexes) and validated for CVD separation and
// 3:1 contrast against BOTH light and dark surfaces, so a series keeps its
// color across a theme toggle.
const CHART_SERIES_PALETTE = [
'#3B82F6', '#16A34A', '#A855F7', '#D97706',
'#0891B2', '#65A30D', '#6366F1', '#EF4444',
];
const ChartThemeBridge = ({ children }) => {
const theme = useTheme();
const hostBridge = React.useMemo(() => ({
textPrimary: theme.text.primary,
textSecondary: theme.text.secondary,
background: theme.backgrounds.surface,
grid: theme.colors.gray?.[3] ?? theme.backgrounds.border ?? '#e5e7eb',
accentPalette: CHART_SERIES_PALETTE,
fontFamily: theme.fontFamily,
}), [theme]);
return <ChartThemeProvider hostThemeBridge={hostBridge}>{children}</ChartThemeProvider>;
};
Notes:
- If you pass a dark
background but no accentPalette, the provider
auto-selects its built-in dark-surface palette (the light one washes out to
~2:1 contrast on dark). An explicit accentPalette always wins.
- The provider also feeds the palette into the module-level color scheme
(
setDefaultColorScheme), so series without explicit colors pick it up.
useChartTheme() reads the merged ChartTheme inside any chart subtree.
Picking a chart type
| Intent |
Use |
| Trend over time |
LineChart, AreaChart, SparklineChart (inline/KPI) |
| Part-to-whole |
PieChart, DonutChart, StackedBarChart, StackedAreaChart, MarimekkoChart |
| Category comparison |
BarChart, GroupedBarChart, RadialBarChart, ParetoChart |
| Correlation / 2–3 variables |
ScatterChart, BubbleChart |
| Distribution |
HistogramChart, ViolinChart, RidgeChart |
| Matrix / intensity |
HeatmapChart |
| Flows and relationships |
SankeyChart, NetworkChart, FunnelChart |
| Financial OHLC |
CandlestickChart |
| Single bounded value |
GaugeChart |
| Multivariate profile |
RadarChart |
| Mixed layers (bar + line + area) |
ComboChart |
Full catalog with exact data-prop shapes: references/api.md.
Data shapes (most common)
- XY charts (
LineChart, AreaChart, ScatterChart): data: ChartDataPoint[]
({ x: number; y: number; id?, label?, color?, size?, data? }) or
series: [{ name, data, color?, ... }] for multi-series.
BarChart: data: BarChartDataPoint[] ({ category: string; value: number; color? });
multi-series via series + layout: 'grouped' | 'stacked' (+ stackMode: '100%').
PieChart / DonutChart: data: { label: string; value: number; color? }[].
SparklineChart: data: number[] | { x, y }[].
- Everything accepts
width/height, title/subtitle, spacing props
(m, mx, p, ...) and accessibility props from BaseChartProps.
Interactions
Per-chart props (Line/Bar/Area/Scatter and most cartesian charts):
- Tooltip:
tooltip={{ show, formatter, backgroundColor, ... }},
liveTooltip (follow pointer), multiTooltip (all series at pointer x),
enableCrosshair.
- Pan/zoom (Line/Scatter):
enablePanZoom, zoomMode: 'x' | 'y' | 'both',
minZoom, enableWheelZoom, wheelZoomStep, invertWheelZoom,
invertPinchZoom, resetOnDoubleTap, clampToInitialDomain,
onDomainChange.
- Events:
onPress, onDataPointPress (typed per chart's datum).
Multiple charts sharing one crosshair/tooltip/zoom: wrap in ChartsProvider
(alias GlobalChartsRoot), give each chart
useOwnInteractionProvider={false} and suppressPopover, and let the provider
render the single shared popover (withPopover, default true). Customize it by
mounting ChartActiveTooltip yourself (render, renderEntry,
renderHeader, filterEntry, sortEntries, maxEntries, offset). See
references/patterns.md.
Streaming / live data
Use useStreamingData(initialData, { maxDataPoints, updateInterval, onDataOverflow })
— returns { data, addDataPoint, startStreaming, stopStreaming, clearData, isStreaming }.
It batches high-frequency points and trims to a rolling window; feed data
straight into a LineChart/AreaChart. For very large static series, pass
decimationThreshold (LineChart) or pre-thin with useDataDecimation
(LTOB, preserves visual trend).
Accessibility
Every chart accepts accessible, accessibilityLabel, accessibilityHint,
accessibilityRole, and importantForAccessibility. Always set an
accessibilityLabel that summarizes the data. PieChart additionally
supports keyboardNavigation and ariaLabelFormatter(slice, percentage).
Pitfalls
- Charts render nothing useful without explicit or inherited size — set
width/height (or size on DonutChart) when the layout doesn't provide one.
accentPalette colors are assigned by series slot in a fixed order; keep the
order stable so series keep their identity across renders and theme switches.
- Inside
ChartsProvider, forgetting useOwnInteractionProvider={false} gives
each chart its own isolated tooltip/zoom state; forgetting suppressPopover
double-renders tooltips.
- Time axes take numeric timestamps (
x: Date.now()) with
xScaleType="time", not Date objects (exception: CandlestickChart
accepts x: number | Date).
- Reanimated misconfiguration in the consumer app breaks animations; as a
debug fallback
LineChart supports disableAnimations.
Anything this skill does not cover
This skill covers the separate @platform-blocks/charts package. Platform
Blocks is much larger — 97 components, 25 charts, and 18 hooks. Do not guess an
API for something outside this scope; fetch the generated docs instead:
| What you need |
Where |
| Index of every page, one line each |
https://platform-blocks.com/llms.txt |
| One component or chart |
https://platform-blocks.com/llms/components/<Name>.md |
| One hook |
https://platform-blocks.com/llms/hooks/<useName>.md |
| Guides |
https://platform-blocks.com/llms/guides/{getting-started,accessibility,localization}.md |
| Everything in one file (~1.3 MB) |
https://platform-blocks.com/llms-full.txt |
<Name> is the exact PascalCase export name — .../llms/components/DataTable.md,
.../llms/components/AreaChart.md. Each page carries the component's full prop
table (type, required, default, description) plus runnable examples, generated
from the source, so it is authoritative where memory is not. When you are unsure
whether something exists or what it is called, read llms.txt first — it lists
every page with a one-line summary.
Import paths (for the @platform-blocks/ui pages above): components come from
the package root (import { X } from '@platform-blocks/ui'). The exceptions are
subpath-only: FormLayout (@platform-blocks/ui/FormLayout), AudioPlayer
(@platform-blocks/ui/AudioPlayer), and the whole Navigation module —
NavigationContainer, createStackNavigator, createDrawerNavigator,
Screen, useNavigation, useRoute (@platform-blocks/ui/Navigation). A few
utilities also live on subpaths (e.g. validationRules on
@platform-blocks/ui/Input). A docs page existing does not guarantee a root
export — HoverCard, for instance, is internal and has no page and no export.
Notably outside this skill:
- The UI library itself (
@platform-blocks/ui) — its 97 components, theme
system, and layout primitives are a different package. Charts are usually
placed inside a Card/Surface from it.
- Install and provider wiring → the
platform-blocks-setup skill.
Bridging chart colors to the app theme is covered above; the theme object
itself is in platform-blocks-theming. Placing charts on a screen →
platform-blocks-layout.
1---2name: platform-blocks-charts3description: Add data visualization to a React Native or Expo app with @platform-blocks/charts. Use when installing the charts package, choosing among its 25 chart types (line, bar, area, pie/donut, scatter, sparkline, heatmap, candlestick, sankey, and more), theming charts to match the app via ChartThemeProvider and hostThemeBridge, wiring tooltips/crosshairs/pan-zoom interactions, or rendering streaming/live data.4---56# Platform Blocks Charts78`@platform-blocks/charts` is a React Native + Web charting library (SVG via9`react-native-svg`, animations via `react-native-reanimated`) with 25 chart10components, a shared interaction engine (tooltips, crosshair, pan/zoom), and a11theme bridge for host design systems. Docs: https://platform-blocks.com1213- Chart catalog + core APIs: `references/api.md`14- Complete copy-paste examples: `references/patterns.md`1516## Install1718```bash19npm install @platform-blocks/charts react-native-svg react-native-reanimated20# Expo: npx expo install react-native-svg react-native-reanimated21```2223Peer dependencies: `react >= 18`, `react-native >= 0.73`,24`react-native-svg >= 13`, `react-native-reanimated >= 3.4`25(`react-dom` optional, web only). Reanimated needs its Babel/worklets plugin26configured in the consuming app.2728## Theming: ChartThemeProvider + hostThemeBridge2930Wrap the app (or any subtree) in `ChartThemeProvider`. Without it, charts use a31light default theme. To match the host app, pass `hostThemeBridge` — all fields32optional: `textPrimary`, `textSecondary`, `background`, `grid`,33`accentPalette` (string[]), `fontFamily`.3435Real pattern from platform-blocks.com (bridging `@platform-blocks/ui`):3637```tsx38import { useTheme } from '@platform-blocks/ui';39import { ChartThemeProvider } from '@platform-blocks/charts';4041// Categorical series palette — fixed hue order, assigned by slot, never cycled.42// Pinned as hex (not theme ramp indexes) and validated for CVD separation and43// 3:1 contrast against BOTH light and dark surfaces, so a series keeps its44// color across a theme toggle.45const CHART_SERIES_PALETTE = [46 '#3B82F6', '#16A34A', '#A855F7', '#D97706',47 '#0891B2', '#65A30D', '#6366F1', '#EF4444',48];4950const ChartThemeBridge = ({ children }) => {51 const theme = useTheme();52 const hostBridge = React.useMemo(() => ({53 textPrimary: theme.text.primary,54 textSecondary: theme.text.secondary,55 background: theme.backgrounds.surface,56 grid: theme.colors.gray?.[3] ?? theme.backgrounds.border ?? '#e5e7eb',57 accentPalette: CHART_SERIES_PALETTE,58 fontFamily: theme.fontFamily,59 }), [theme]);60 return <ChartThemeProvider hostThemeBridge={hostBridge}>{children}</ChartThemeProvider>;61};62```6364Notes:65- If you pass a dark `background` but no `accentPalette`, the provider66 auto-selects its built-in dark-surface palette (the light one washes out to67 ~2:1 contrast on dark). An explicit `accentPalette` always wins.68- The provider also feeds the palette into the module-level color scheme69 (`setDefaultColorScheme`), so series without explicit colors pick it up.70- `useChartTheme()` reads the merged `ChartTheme` inside any chart subtree.7172## Picking a chart type7374| Intent | Use |75|---|---|76| Trend over time | `LineChart`, `AreaChart`, `SparklineChart` (inline/KPI) |77| Part-to-whole | `PieChart`, `DonutChart`, `StackedBarChart`, `StackedAreaChart`, `MarimekkoChart` |78| Category comparison | `BarChart`, `GroupedBarChart`, `RadialBarChart`, `ParetoChart` |79| Correlation / 2–3 variables | `ScatterChart`, `BubbleChart` |80| Distribution | `HistogramChart`, `ViolinChart`, `RidgeChart` |81| Matrix / intensity | `HeatmapChart` |82| Flows and relationships | `SankeyChart`, `NetworkChart`, `FunnelChart` |83| Financial OHLC | `CandlestickChart` |84| Single bounded value | `GaugeChart` |85| Multivariate profile | `RadarChart` |86| Mixed layers (bar + line + area) | `ComboChart` |8788Full catalog with exact data-prop shapes: `references/api.md`.8990## Data shapes (most common)9192- XY charts (`LineChart`, `AreaChart`, `ScatterChart`): `data: ChartDataPoint[]`93 (`{ x: number; y: number; id?, label?, color?, size?, data? }`) or94 `series: [{ name, data, color?, ... }]` for multi-series.95- `BarChart`: `data: BarChartDataPoint[]` (`{ category: string; value: number; color? }`);96 multi-series via `series` + `layout: 'grouped' | 'stacked'` (+ `stackMode: '100%'`).97- `PieChart` / `DonutChart`: `data: { label: string; value: number; color? }[]`.98- `SparklineChart`: `data: number[] | { x, y }[]`.99- Everything accepts `width`/`height`, `title`/`subtitle`, spacing props100 (`m`, `mx`, `p`, ...) and accessibility props from `BaseChartProps`.101102## Interactions103104Per-chart props (Line/Bar/Area/Scatter and most cartesian charts):105- Tooltip: `tooltip={{ show, formatter, backgroundColor, ... }}`,106 `liveTooltip` (follow pointer), `multiTooltip` (all series at pointer x),107 `enableCrosshair`.108- Pan/zoom (Line/Scatter): `enablePanZoom`, `zoomMode: 'x' | 'y' | 'both'`,109 `minZoom`, `enableWheelZoom`, `wheelZoomStep`, `invertWheelZoom`,110 `invertPinchZoom`, `resetOnDoubleTap`, `clampToInitialDomain`,111 `onDomainChange`.112- Events: `onPress`, `onDataPointPress` (typed per chart's datum).113114Multiple charts sharing one crosshair/tooltip/zoom: wrap in `ChartsProvider`115(alias `GlobalChartsRoot`), give each chart116`useOwnInteractionProvider={false}` and `suppressPopover`, and let the provider117render the single shared popover (`withPopover`, default true). Customize it by118mounting `ChartActiveTooltip` yourself (`render`, `renderEntry`,119`renderHeader`, `filterEntry`, `sortEntries`, `maxEntries`, `offset`). See120`references/patterns.md`.121122## Streaming / live data123124Use `useStreamingData(initialData, { maxDataPoints, updateInterval, onDataOverflow })`125— returns `{ data, addDataPoint, startStreaming, stopStreaming, clearData, isStreaming }`.126It batches high-frequency points and trims to a rolling window; feed `data`127straight into a `LineChart`/`AreaChart`. For very large static series, pass128`decimationThreshold` (LineChart) or pre-thin with `useDataDecimation`129(LTOB, preserves visual trend).130131## Accessibility132133Every chart accepts `accessible`, `accessibilityLabel`, `accessibilityHint`,134`accessibilityRole`, and `importantForAccessibility`. Always set an135`accessibilityLabel` that summarizes the data. `PieChart` additionally136supports `keyboardNavigation` and `ariaLabelFormatter(slice, percentage)`.137138## Pitfalls139140- Charts render nothing useful without explicit or inherited size — set141 `width`/`height` (or `size` on `DonutChart`) when the layout doesn't provide one.142- `accentPalette` colors are assigned by series slot in a fixed order; keep the143 order stable so series keep their identity across renders and theme switches.144- Inside `ChartsProvider`, forgetting `useOwnInteractionProvider={false}` gives145 each chart its own isolated tooltip/zoom state; forgetting `suppressPopover`146 double-renders tooltips.147- Time axes take numeric timestamps (`x: Date.now()`) with148 `xScaleType="time"`, not `Date` objects (exception: `CandlestickChart`149 accepts `x: number | Date`).150- Reanimated misconfiguration in the consumer app breaks animations; as a151 debug fallback `LineChart` supports `disableAnimations`.152153## Anything this skill does not cover154155This skill covers the separate `@platform-blocks/charts` package. Platform156Blocks is much larger — 97 components, 25 charts, and 18 hooks. Do not guess an157API for something outside this scope; fetch the generated docs instead:158159| What you need | Where |160| --- | --- |161| Index of every page, one line each | `https://platform-blocks.com/llms.txt` |162| One component or chart | `https://platform-blocks.com/llms/components/<Name>.md` |163| One hook | `https://platform-blocks.com/llms/hooks/<useName>.md` |164| Guides | `https://platform-blocks.com/llms/guides/{getting-started,accessibility,localization}.md` |165| Everything in one file (~1.3 MB) | `https://platform-blocks.com/llms-full.txt` |166167`<Name>` is the exact PascalCase export name — `.../llms/components/DataTable.md`,168`.../llms/components/AreaChart.md`. Each page carries the component's full prop169table (type, required, default, description) plus runnable examples, generated170from the source, so it is authoritative where memory is not. When you are unsure171whether something exists or what it is called, read `llms.txt` first — it lists172every page with a one-line summary.173174Import paths (for the `@platform-blocks/ui` pages above): components come from175the package root (`import { X } from '@platform-blocks/ui'`). The exceptions are176subpath-only: `FormLayout` (`@platform-blocks/ui/FormLayout`), `AudioPlayer`177(`@platform-blocks/ui/AudioPlayer`), and the whole `Navigation` module —178`NavigationContainer`, `createStackNavigator`, `createDrawerNavigator`,179`Screen`, `useNavigation`, `useRoute` (`@platform-blocks/ui/Navigation`). A few180utilities also live on subpaths (e.g. `validationRules` on181`@platform-blocks/ui/Input`). A docs page existing does not guarantee a root182export — `HoverCard`, for instance, is internal and has no page and no export.183184Notably outside this skill:185186- **The UI library itself** (`@platform-blocks/ui`) — its 97 components, theme187 system, and layout primitives are a different package. Charts are usually188 placed inside a `Card`/`Surface` from it.189- **Install and provider wiring** → the `platform-blocks-setup` skill.190 **Bridging chart colors to the app theme** is covered above; the theme object191 itself is in `platform-blocks-theming`. **Placing charts on a screen** →192 `platform-blocks-layout`.