60 fps ยท Skia-powered ยท 10K+ candles ยท Zero jank
๐ Documentation ยท ๐ฎ Live Demo ยท ๐ Report Bug ยท ๐ฌ Discussions
Every React Native trading app needs a candlestick chart. Every existing solution either wraps a WebView (laggy), bridges a native chart library (heavy), or builds on react-native-svg (slow at scale).
react-native-kline-chart takes a different approach: it draws directly on a Skia canvas using PictureRecorder, bypasses React reconciliation entirely, and runs all gestures as Reanimated worklets on the UI thread.
The result? Butter-smooth 60 fps with 10,000+ candles. No bridge. No WebView. No compromises.
| Feature | Details | |
|---|---|---|
| โก | Skia Rendering | Immediate-mode drawing via PictureRecorder โ zero React component overhead per candle |
| ๐ค | Native Gestures | Pan, pinch-to-zoom, long-press crosshair โ all Reanimated worklets on the UI thread |
| ๐ | 10K+ Candles | Viewport clipping ensures only visible candles are drawn โ zero jank at scale |
| ๐ | MA Indicators | Built-in moving average lines with configurable periods and colors (MA5, MA10, MA20โฆ) |
| ๐ฏ | Crosshair + Info Panel | Long-press to reveal precision crosshair with OHLC, change %, and amplitude |
| ๐น | Last Price Line | Dashed line showing the latest close price in real-time |
| ๐ท๏ธ | High / Low Markers | Visible extremes annotated directly on the chart |
| ๐จ | Fully Customizable | Colors, sizes, spacing, indicators โ dark theme ready out of the box |
npm install react-native-kline-chartnpm install @shopify/react-native-skia react-native-reanimated react-native-gesture-handlerAdd the Reanimated Babel plugin:
// babel.config.js
module.exports = {
plugins: ['react-native-reanimated/plugin'],
};import { KlineChart } from 'react-native-kline-chart';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
export default function App() {
const data = [
{ time: 1700000000000, open: 100, high: 105, low: 98, close: 103 },
{ time: 1700000060000, open: 103, high: 107, low: 101, close: 99 },
// ...more candles
];
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<KlineChart
data={data}
width={400}
height={600}
showMA
showCrosshair
/>
</GestureHandlerRootView>
);
}That's it. Three imports, one component, production-ready charts.
| Prop | Type | Default | Description |
|---|---|---|---|
data |
Candle[] |
required | Array of candle data |
width |
number |
required | Canvas width in pixels |
height |
number |
required | Canvas height in pixels |
candleWidth |
number |
8 |
Width of each candle body |
candleSpacing |
number |
3 |
Gap between candles |
minCandleWidth |
number |
2 |
Min candle width when zooming out |
maxCandleWidth |
number |
24 |
Max candle width when zooming in |
bullishColor |
string |
'#2DC08E' |
Bullish (close โฅ open) candle color |
bearishColor |
string |
'#F6465D' |
Bearish candle color |
showMA |
boolean |
true |
Show moving average lines |
maPeriods |
number[] |
[5, 10] |
MA periods |
maColors |
string[] |
['#F7931A', '#5B8DEF', '#C084FC'] |
MA line colors |
showCrosshair |
boolean |
true |
Enable long-press crosshair |
backgroundColor |
string |
'#0B0E11' |
Chart background color |
gridColor |
string |
'rgba(255,255,255,0.2)' |
Grid line color |
textColor |
string |
'rgba(255,255,255,0.35)' |
Axis label color |
crosshairColor |
string |
'rgba(255,255,255,0.3)' |
Crosshair line color |
rightPaddingCandles |
number |
20 |
Right padding (in candle widths) |
onCrosshairChange |
(candle: Candle | null) => void |
โ | Crosshair activation callback |
type Candle = {
time: number; // timestamp in milliseconds
open: number;
high: number;
low: number;
close: number;
};import { KlineChart, computeMA } from 'react-native-kline-chart';
import type { Candle, KlineChartProps } from 'react-native-kline-chart';โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ JS Thread โ
โ useMemo โ pre-compute MA values โ
โ useChartData โ flatten candle data to Float64 โ
โโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ SharedValue
โโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ UI Thread โ
โ useDerivedValue โ PictureRecorder โ draw all โ
โ Gesture worklets โ pan / pinch / long-press โ
โ Viewport clipping โ only visible candles drawn โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Why it's fast:
- Skia
PictureRecorderbatches all draw calls โ no React reconciliation per candle - All gesture handlers run as Reanimated worklets โ never touch the JS thread
- Candle/wick geometry is batched into 4 Skia
Pathobjects (bull body, bear body, bull wick, bear wick) - Paint objects are reused across frames
- Thousand-separator formatting runs inside worklets
cd example
npm install
cd ios && pod install && cd ..
npx react-native run-iosPRs welcome! Please open an issue first to discuss what you'd like to change.

