Canvas-powered, JSX-composable candlestick charts for React, for trading UIs.
Build responsive trading charts in React with candlesticks, indicators, crosshairs, zoom, and theming — rendered on Canvas for smooth performance on large datasets.
react-candlesticks is in an early public release / soft launch phase. Feedback, bug reports, and edge-case reproductions are especially helpful.
Website • Documentation • npm • Live Demo
For bugs and feature requests, open an issue. For usage questions, start a discussion.
npm install react-candlesticksPaste this into your React app for a basic candlestick chart with volume:
import 'react-candlesticks/style.css';
import { Chart, Panel, Candlesticks, VolumeBars, exampleData }
from 'react-candlesticks';
export default function App() {
return (
<Chart
width={800}
height={500}
granularity="d1"
data={exampleData} // demo data
>
<Panel heightRatio={3}>
<Candlesticks />
</Panel>
<Panel>
<VolumeBars />
</Panel>
</Chart>
);
}granularity is optional if your dataset uses a consistent interval and you want the library to infer it automatically. For empty/loading states, pass granularity explicitly.
For a fuller walkthrough, see the Getting Started docs.
- Composable like React — build charts using JSX (React components)
- Canvas rendering — predictable performance on large datasets
- Trading-focused — indicators, crosshairs, multi-panel layouts
- Nice feeling pan and zoom — mouse, mouse wheel, trackpad, touch
- Fully themeable — light and dark mode, or provide a custom theme
- Lightweight & dependency-free — no core dependencies (other than React and ReactDOM peer dependencies)
The recommended approach for most use cases. Compose panels and layers declaratively using JSX.
import { Chart, Panel, Candlesticks, VolumeBars, BollingerBands, EMA, MACD, RSI }
from 'react-candlesticks';
<Chart granularity="d1" data={data}>
<Panel heightRatio={3}>
<Candlesticks />
<EMA period={50} />
<BollingerBands />
</Panel>
<Panel>
<VolumeBars />
</Panel>
<Panel>
<MACD />
</Panel>
<Panel>
<RSI />
</Panel>
</Chart>import { Chart } from 'react-candlesticks';
<Chart
granularity="d1"
data={data}
panels={[
{
heightRatio: 3,
layers: [
{ type: 'price:candlesticks' },
{ type: 'ema', period: 20 },
{ type: 'bollinger-bands' },
]
},
{
layers: [{ type: 'volume:bars' }]
},
{
layers: [{ type: 'macd' }]
},
{
layers: [{ type: 'rsi' }]
}
]}
/>Use defineLayer to add an indicator implementation to a specific chart. A
definition controls config parsing, calculation, and Canvas drawing, and
provides a JSX component through its Component property.
import {
Candlesticks,
Chart,
Panel,
defineLayer,
drawLineSeries,
parseLineConfig,
} from 'react-candlesticks';
const doubleClose = defineLayer({
type: 'custom:double-close',
parseConfig: (config, _theme, panelId) => ({
...config,
id: config.id ?? `double-close_${panelId}`,
type: 'custom:double-close',
indicator: true,
// Share the candlestick price scale so doubled values use price coordinates.
defaultScale: { key: 'price_auto', domain: 'price', range: { type: 'auto' } },
scale: config.scale ?? null,
scalePolicy: 'derived',
requiredInputKeys: ['input'],
inputs: config.inputs ?? [
{ key: 'input', source: { type: 'price', field: 'close' } },
],
outputs: ['value'],
period: 1,
offset: 0,
lookback: 0,
calculate: true,
includeInAutoScale: true,
valueToY: (min, max, top, height) =>
value => top + ((max - value) / (max - min)) * height,
legend: null,
yAxis: null,
valueLabelFormatter: String,
}),
calculate: (_config, inputs, outputs, start, end) => {
for (let index = start; index < end; index++) {
outputs.value[index] = inputs.input.values[index] * 2;
}
},
draw: (
context, _axes, _chart, _panel, config, _layout, viewport,
_chartMetrics, _panelMetrics, layerMetrics,
) => {
const values =
viewport.layersData.layerDataInstances[config.id].outputValues.value;
const { intervalSize, scrollOffset } = viewport.timeScale.metadata;
drawLineSeries({
context,
values,
lineConfig: parseLineConfig({ color: '#8b5cf6', width: 2 })!,
valueToY: layerMetrics.valueToY,
startBarIndex: viewport.timeScale.startBarIndex,
endBarIndex: viewport.timeScale.endBarIndex,
intervalSize,
scrollOffset,
});
},
});
const DoubleClose = doubleClose.Component;
<Chart data={data} customLayers={[doubleClose]}>
<Panel>
<Candlesticks />
<DoubleClose />
</Panel>
</Chart>Custom type names must not collide with built-in or other custom layer types. Definitions are chart-scoped, so separate charts can use independent custom layer sets without global registration.
Use renderMode="minimal" when rendering many small charts per screen (for example, watchlist rows or card grids).
This mode defaults to a lighter configuration by disabling interaction and non-essential chart chrome unless you explicitly opt back in.
<Chart
renderMode="minimal"
pixelRatio={1}
width={120}
height={60}
data={data}
>
<Panel>
<Candlesticks yAxis={false} legend={false} />
</Panel>
</Chart>renderMode="minimal"defaultscrosshairs,grid,xAxis,borders,enableScroll, andenableZoomtofalse.- You can still override any of these explicitly.
pixelRatiodefaults to'device'; setpixelRatio={1}for cheaper rendering in dense lists.
Enable y-scale smoothing to reduce abrupt vertical rescaling while panning.
<Chart data={data} scaleSmoothing />
<Chart
data={data}
scaleSmoothing={{ durationMs: 240, expandImmediate: true }}
/>Use a ChartHandle ref when external UI needs to drive the viewport or crosshair.
import { useRef, useState } from 'react';
import type { ChartHandle, ChartViewport } from 'react-candlesticks';
import { Candlesticks, Chart, Panel, VolumeBars } from 'react-candlesticks';
function ControlledChart({ data }) {
const chartRef = useRef<ChartHandle>(null);
const [viewport, setViewport] = useState<ChartViewport | null>(null);
const highlighted = data[Math.floor(data.length * 0.7)];
return (
<>
<button
type="button"
onClick={() => chartRef.current?.setVisibleRange({
from: data.length - 120,
to: data.length - 40,
marginBars: 6,
})}
>
Show range
</button>
<button type="button" onClick={() => chartRef.current?.fitContent({ marginBars: 8 })}>
Fit
</button>
<button type="button" onClick={() => chartRef.current?.scrollToLatest({ marginBars: 8 })}>
Latest
</button>
<button
type="button"
onClick={() => chartRef.current?.setCrosshairPosition({
timestamp: highlighted.time,
value: highlighted.close,
panelId: 'price',
})}
>
Crosshair
</button>
<Chart
ref={chartRef}
data={data}
onViewportChange={setViewport}
userViewportCallbackMode="debounce"
userViewportCallbackDebounceMs={120}
>
<Panel id="price" heightRatio={3}>
<Candlesticks />
</Panel>
<Panel id="volume">
<VolumeBars />
</Panel>
</Chart>
{viewport && (
<output>
{viewport.startBarIndex}-{viewport.endBarIndex}
</output>
)}
</>
);
}setCrosshairPosition() gives pointer movement control again as soon as the user moves over the chart. Pass { lock: true } as the second argument to keep the programmatic crosshair fixed until clearCrosshairPosition() is called.
User-driven viewport callbacks default to one notification per animation frame. Use userViewportCallbackMode="debounce" for heavier React state updates, "sync" for every internal viewport update, or "none" when you only need imperative reads through getViewport().
Use the built-in 'light' or 'dark' theme, or provide a partial Theme object.
import type { Theme } from 'react-candlesticks';
// Named theme
<Chart theme="dark" ... />
const myCustomTheme: Theme = {
base: 'dark',
chart: {
backgroundColor: '#101820',
},
indicators: {
line: { width: 2 },
linePalette: ['#ffd166', '#5dd9c1', '#c77dff'],
},
layers: {
sma: {
series: {
value: { color: '#ffd166', width: 3 },
},
},
},
};
// Custom partial theme
<Chart theme={myCustomTheme} ... />See the Theme documentation for the full theme shape.
- Supports React 18+ and React 19.
- Ships ESM only; CommonJS/UMD consumers are not supported.
- Intended for modern browser-based React apps.
- Chart rendering and interaction are client-side. In SSR frameworks, render the chart from a client component or client-only boundary.
- Runtime behavior depends on standard browser APIs including Canvas,
ResizeObserver,matchMedia,devicePixelRatio, and Pointer Events for touch and pinch interactions. - If you target older browsers or restricted webviews, you may need compatibility checks or polyfills for APIs such as
ResizeObserver. - Current chart time display defaults to
UTC. A public chart-level timezone configuration API is not exposed yet, so if your UI requires exchange-local or user-local time labels, treat that as a current limitation. - Mouse, trackpad, touch, and pinch interactions are covered in modern evergreen browsers. If you rely on embedded webviews, older Safari/WebKit builds, or custom kiosk environments, verify pointer and wheel behavior in your exact target runtime before rollout.
- Data should use a consistent interval if you want automatic
granularityinference. For irregular datasets, passgranularityexplicitly.
| Layer | Type string | Description |
|---|---|---|
<Candlesticks> |
'price:candlesticks' |
OHLC candlestick chart |
<PriceLine> |
'price:line' |
Line chart of a single price field |
<VolumeBars> |
'volume:bars' |
Volume bar chart |
<ADX> |
'adx' |
Average Directional Index |
<ATR> |
'atr' |
Average True Range |
<BollingerBands> |
'bollinger-bands' |
Bollinger Bands overlay |
<CCI> |
'cci' |
Commodity Channel Index |
<EMA> |
'ema' |
Exponential Moving Average |
<MACD> |
'macd' |
MACD oscillator |
<OBV> |
'obv' |
On-Balance Volume |
<ParabolicSAR> |
'parabolic-sar' |
Parabolic Stop and Reverse overlay |
<RSI> |
'rsi' |
Relative Strength Index |
<SMA> |
'sma' |
Simple Moving Average |
<Stochastic> |
'stochastic' |
Stochastic Oscillator |
<WilliamsR> |
'williams-r' |
Williams %R oscillator |
30 July 2026 · 4 min read · Intro
An open-source React/TypeScript library for composable financial charts with candlesticks, volume, indicators, theming, custom layers, and drawings.
Jul 2, 2026 · 6 min read · Guides
Build an interactive React candlestick chart in Next.js with volume bars, SMA overlays, a Stochastic indicator, and light and dark themes.
Jun 29, 2026 · 9 min read · Guides
Fetch free crypto OHLCV data and build a React crypto chart with granularity controls, chart type switching, volume, and removable indicators.
Jun 7, 2026 · 7 min read · Guides
Build an interactive OHLC chart with volume bars, technical indicators, crosshairs, zoom, and dark mode.
If you want runtime prop validation in a JavaScript app, install the optional peer dependency too:
npm install react-candlesticks prop-typesThen import Chart from the opt-in propTypes entrypoint:
import { Chart } from 'react-candlesticks/propTypes';