react-klinecharts
v1.0.0
Published
A flexible React wrapper for KlineCharts with hooks, declarative sub-components, and full TypeScript support
Maintainers
Readme
react-klinecharts
A flexible React wrapper for KlineCharts with hooks, declarative sub-components, and full TypeScript support.
- Declarative props for all reactive chart settings
<KLineChart.Indicator>,<KLineChart.Overlay>,<KLineChart.Widget>and<KLineChart.YAxis>sub-components- Hooks:
useKLineChart,useIndicator,useOverlay,useYAxis,useChartEvent,useCrosshair,useVisibleRange,useBarSpace,useDataList,usePane,useYAxes - Strongly typed event callbacks — no more
as Crosshaircasts - Full imperative access via ref
- Re-exports all klinecharts types and utilities
- StrictMode-safe, no extra dependencies (klinecharts manages its own
ResizeObserver)
Installation
pnpm add react-klinecharts
# or
npm install react-klinechartsPeer dependencies: react >= 17, react-dom >= 17.
Quick Start
import { KLineChart, type Chart } from "react-klinecharts";
import { useRef } from "react";
function App() {
const chartRef = useRef<Chart>(null);
const data = [
{ timestamp: 1680000000000, open: 28000, high: 28500, low: 27800, close: 28200, volume: 100 },
// ...
]
return (
<KLineChart
ref={chartRef}
data={data}
symbol={{ ticker: "BTC/USDT" }}
period={{ type: "minute", span: 15 }}
style={{ width: "100%", height: 600 }}
>
<KLineChart.Indicator value={{ name: "MA", calcParams: [5, 10, 30] }} />
<KLineChart.Indicator value="VOL" pane={{ height: 80 }} />
</KLineChart>
);
}API Reference
<KLineChart>
The core component. Manages chart lifecycle, provides context for hooks and sub-components.
All standard HTML div attributes (className, style, id, etc.) are passed through to the container element. The native DOM onScroll handler is passed through unchanged; chart scroll events use onChartScroll instead.
Init-only Props
| Prop | Type | Description |
|------|------|-------------|
| options | Options | Chart initialization options. Applied once on mount. |
Data Props
| Prop | Type | Description |
|------|------|-------------|
| data | KLineData[] | Static data array. Replacing the array re-applies the data (use dataLoader for streaming). |
| dataLoader | DataLoader | Data loader with getBars, subscribeBar, unsubscribeBar. Calls setDataLoader. |
| symbol | SymbolInfo | Symbol info (ticker, precision). Calls setSymbol. |
| period | Period | Time period ({ type, span }). Calls setPeriod. |
Reactive Props
These props are synced to the chart instance via useEffect. Changing them updates the chart without re-initialization.
| Prop | Type | Chart Method |
|------|------|-------------|
| styles | string \| DeepPartial<Styles> | setStyles() |
| locale | string | setLocale() |
| timezone | string | setTimezone() |
| formatter | Partial<Formatter> | setFormatter() |
| thousandsSeparator | Partial<ThousandsSeparator> | setThousandsSeparator() |
| decimalFold | Partial<DecimalFold> | setDecimalFold() |
| zoomEnabled | boolean | setZoomEnabled() |
| scrollEnabled | boolean | setScrollEnabled() |
| zoomAnchor | ZoomAnchorType \| Partial<ZoomAnchor> | setZoomAnchor() |
| offsetRightDistance | number | setOffsetRightDistance() |
| maxOffsetLeftDistance | number | setMaxOffsetLeftDistance() |
| maxOffsetRightDistance | number | setMaxOffsetRightDistance() |
| leftMinVisibleBarCount | number | setLeftMinVisibleBarCount() |
| rightMinVisibleBarCount | number | setRightMinVisibleBarCount() |
| barSpace | number | setBarSpace() |
| hotkey | Partial<Hotkey> | setHotkey() |
| xAxis | XAxisOverride | overrideXAxis() |
| yAxis | YAxisOverride | overrideYAxis() |
Event Callbacks
Event callbacks are strongly typed: the data argument matches the payload klinecharts emits for that action. For example, onCrosshairChange receives a Crosshair and onCandleBarClick receives the clicked KLineData — no casts required.
| Prop | Signature | Description |
|------|-----------|-------------|
| onReady | (chart: Chart) => void | Fired after chart initialization |
| onZoom | (data: { scale: number }) => void | Chart zoom event |
| onChartScroll | (data: { distance: number }) => void | Chart scroll event (klinecharts onScroll action; renamed to avoid colliding with the native DOM onScroll) |
| onVisibleRangeChange | (data: VisibleRange) => void | Visible data range changed |
| onCrosshairChange | (data: Crosshair) => void | Crosshair position changed |
| onCandleBarClick | (data: KLineData) => void | Candle bar clicked |
| onPaneDrag | (data: { paneId: string }) => void | Pane drag event |
| onCandleTooltipFeatureClick | (data: unknown) => void | Candle tooltip feature clicked |
| onIndicatorTooltipFeatureClick | (data: unknown) => void | Indicator tooltip feature clicked |
| onCrosshairFeatureClick | (data: unknown) => void | Crosshair feature clicked |
<KLineChart.Indicator>
Declarative indicator management. Renders nothing — purely manages indicator lifecycle.
<KLineChart.Indicator
value={{ name: "MA", calcParams: [5, 10, 30] }}
isStack={false}
pane={{ height: 100 }}
/>
// Or simply by name:
<KLineChart.Indicator value="VOL" />| Prop | Type | Description |
|------|------|-------------|
| value | string \| IndicatorCreate | Indicator name or full config |
| isStack | boolean | Stack on existing indicators in same pane |
| pane | Partial<PaneOptions> | Options applied to the indicator pane via setPaneOptions (e.g. { height: 80 }) |
| yAxis | YAxisOverride | Y axis config for the indicator pane, applied via createYAxis |
v10 note: klinecharts 10.0.0 changed
createIndicator(value, isStack)—paneId/yAxisIdare now properties of theIndicatorCreatevalue itself.useIndicatorreturns the indicator id (not the pane id).
<KLineChart.YAxis>
Declarative standalone Y axis management. KLineCharts v10 supports multiple Y axes per pane. Renders nothing — purely manages the axis lifecycle via createYAxis / overrideYAxis / removeYAxis.
<KLineChart.YAxis value={{ paneId: "candle", position: "left" }} />| Prop | Type | Description |
|------|------|-------------|
| value | YAxisOverride | Y axis config. createYAxis is idempotent, so changing value re-applies safely. |
<KLineChart.Overlay>
Declarative overlay (drawing tool) management. Renders nothing — purely manages overlay lifecycle.
<KLineChart.Overlay
value={{
name: "segment",
points: [
{ timestamp: 1234567890000, value: 100 },
{ timestamp: 1234567900000, value: 200 },
],
}}
/>| Prop | Type | Description |
|------|------|-------------|
| value | string \| OverlayCreate \| Array<string \| OverlayCreate> | Overlay config(s) |
<KLineChart.Widget>
Declarative portal component that injects standard HTML/React elements directly into the chart DOM utilizing createPortal and the native chart.getDom() method.
If the target pane has not been laid out yet (e.g. an indicator pane that is created asynchronously), the widget retries on the next animation frame until the node is available.
<KLineChart.Widget paneId="candle" position="main">
<div className="custom-tooltip">My interactive React tooltip!</div>
</KLineChart.Widget>| Prop | Type | Description |
|------|------|-------------|
| paneId | string | ID of the pane to inject into (e.g. "candle", "xAxis", or custom indicator pane IDs). If undefined, binds to root container. |
| position | "root" \| "main" \| "yAxis" | Layer position relative to the pane. Default is "main". |
Hooks
useKLineChart()
Access the Chart instance from any descendant of <KLineChart>.
function MyComponent() {
const chart = useKLineChart();
// chart is Chart | null
return <button onClick={() => chart?.scrollToRealTime()}>Go to now</button>;
}State-tracking hooks
These hooks subscribe to chart actions and re-render the host component when the tracked value changes. They return null (or an empty array for usePane()) before the chart is initialized.
| Hook | Returns | Re-renders on |
|------|---------|---------------|
| useCrosshair() | Crosshair \| null | onCrosshairChange |
| useVisibleRange() | VisibleRange \| null | onVisibleRangeChange |
| useBarSpace() | BarSpace \| null | onVisibleRangeChange (covers zoom/resize) |
| useDataList() | KLineData[] \| null | onVisibleRangeChange |
| usePane() / usePane(id) | PaneOptions[] or Nullable<PaneOptions> | onVisibleRangeChange |
| useYAxes(filter?) | YAxis[] | onVisibleRangeChange |
function CrosshairInfo() {
const crosshair = useCrosshair();
if (!crosshair?.kLineData) return <span>Hover the chart</span>;
return <span>{crosshair.kLineData.close}</span>;
}useIndicator(options)
Manages indicator lifecycle. Creates on mount, removes on unmount, overrides on config change.
function MyIndicator() {
const paneId = useIndicator({
value: { name: "RSI", calcParams: [14] },
pane: { height: 80 },
});
return null;
}useOverlay(options)
Manages overlay lifecycle. Creates on mount, removes on unmount, overrides on config change.
function MyOverlay() {
const id = useOverlay({
value: { name: "priceLine", points: [{ value: 50000 }] },
});
return null;
}useYAxis(options)
Manages a standalone Y axis lifecycle. Creates via createYAxis on mount, overrides on change, removes on unmount. Returns the axis id.
function MyYAxis() {
const id = useYAxis({ value: { paneId: "candle", position: "left" } });
return null;
}useYAxes(filter?)
Reactive read of the chart's Y axes. Returns YAxis[] and re-renders on visible-range change.
function AxisCount() {
const axes = useYAxes({ paneId: "candle" });
return <span>{axes.length} axis(es)</span>;
}useChartEvent(type, callback)
Subscribe to any chart action event with a stable ref-based handler. The callback is strongly typed based on the action type.
function Logger() {
useChartEvent("onCrosshairChange", (crosshair) => {
console.log("Crosshair:", crosshair.x, crosshair.y);
});
return null;
}Available event types: "onZoom", "onScroll", "onVisibleRangeChange", "onCrosshairChange", "onCandleBarClick", "onPaneDrag", "onCandleTooltipFeatureClick", "onIndicatorTooltipFeatureClick", "onCrosshairFeatureClick".
Imperative API (ref)
For operations not covered by declarative props, use the Chart ref:
const chartRef = useRef<Chart>(null);
// Navigation
chartRef.current?.scrollToRealTime(300);
chartRef.current?.scrollToTimestamp(timestamp);
chartRef.current?.zoomAtCoordinate(1.5);
// Data queries
chartRef.current?.getDataList();
chartRef.current?.getVisibleRange();
chartRef.current?.getBarSpace();
// Coordinate conversion
chartRef.current?.convertToPixel(points, filter);
chartRef.current?.convertFromPixel(coordinates, filter);
// Export
chartRef.current?.getConvertPictureUrl(true, "png");
// DOM access
chartRef.current?.getDom(paneId, position);
chartRef.current?.getSize(paneId, position);
// Pane management
chartRef.current?.setPaneOptions(options);
chartRef.current?.getPaneOptions(id);
// Y axis management (v10 multi-YAxis)
chartRef.current?.createYAxis(yAxisOverride);
chartRef.current?.removeYAxis({ id });
chartRef.current?.getYAxes(filter);
chartRef.current?.overrideYAxis(yAxisOverride);
// Imperative indicator/overlay operations
chartRef.current?.createIndicator(value, isStack);
chartRef.current?.getIndicators(filter);
chartRef.current?.createOverlay(value);
chartRef.current?.getOverlays(filter);See the full KlineCharts API documentation for all available methods.
Registration Functions
Module-level registration functions are re-exported from klinecharts:
import {
registerIndicator,
registerOverlay,
registerFigure,
registerLocale,
registerStyles,
registerXAxis,
registerYAxis,
registerHotkey,
} from "react-klinecharts";
// Register a custom indicator
registerIndicator({
name: "MyIndicator",
calc: (dataList) => {
return dataList.map((d) => ({ value: d.close }));
},
figures: [{ key: "value", title: "VAL: ", type: "line" }],
});Type Re-exports
All klinecharts types are re-exported for convenience, plus the wrapper's own helper types:
import type {
Chart,
KLineData,
Styles,
Options,
Indicator,
IndicatorCreate,
Overlay,
OverlayCreate,
Crosshair,
ActionType,
ActionCallback,
DataLoader,
SymbolInfo,
Period,
// wrapper-specific
ActionPayloadMap,
TypedActionCallback,
// ... all klinecharts types
} from "react-klinecharts";Examples
Custom Indicator with Hooks
function BollingerBands({ period = 20 }: { period?: number }) {
useIndicator({
value: { name: "BOLL", calcParams: [period, 2] },
});
return null;
}
function App() {
const [period, setPeriod] = useState(20);
return (
<KLineChart dataLoader={loader} symbol={symbol} period={period}>
<BollingerBands period={period} />
</KLineChart>
);
}Theming
<KLineChart
dataLoader={loader}
symbol={symbol}
period={period}
styles={{
grid: { show: false },
candle: {
type: "area",
area: {
lineColor: "#2196F3",
backgroundColor: [
{ offset: 0, color: "rgba(33, 150, 243, 0.3)" },
{ offset: 1, color: "rgba(33, 150, 243, 0)" },
],
},
},
}}
/>Custom Locale
import { registerLocale } from "react-klinecharts";
registerLocale("ru-RU", {
time: "Время",
open: "Откр.",
high: "Макс.",
low: "Мин.",
close: "Закр.",
volume: "Объём",
change: "Изм.",
turnover: "Оборот",
second: "сек",
minute: "мин",
hour: "час",
day: "дн",
week: "нед",
month: "мес",
year: "год",
});
<KLineChart locale="ru-RU" ... />Architecture
src/
index.ts # Public API barrel export
types.ts # React-specific types (props, payload maps)
events.ts # ActionPayloadMap + TypedActionCallback
subscribeChartAction.ts # Shared action subscribe/unsubscribe helper
KLineChartContext.ts # React context for chart instance
KLineChart.tsx # Core component
hooks/
useKLineChart.ts # Context-based chart access
useChartEvent.ts # Typed event subscription hook
useIndicator.ts # Indicator lifecycle hook
useOverlay.ts # Overlay lifecycle hook
useYAxis.ts # Y axis lifecycle hook
useCrosshair.ts # Reactive crosshair state
useVisibleRange.ts # Reactive visible range
useBarSpace.ts # Reactive bar space
useDataList.ts # Reactive data list
usePane.ts # Reactive pane options
useYAxes.ts # Reactive Y axes
components/
Indicator.tsx # <KLineChart.Indicator>
Overlay.tsx # <KLineChart.Overlay>
Widget.tsx # <KLineChart.Widget>
YAxis.tsx # <KLineChart.YAxis>Design principles:
- Thin wrapper — never re-implements what klinecharts already does
- Reactive props drive
useEffectcalls to chart methods - Ref escape hatch exposes the full
Chartinstance for imperative operations - Context enables hooks and sub-components in descendants
- Stable event subscriptions — callbacks stored in refs, no re-subscribe churn
- Strongly typed events — payloads carry their real types
- StrictMode-safe — React unmounts children before parent, so indicators/overlays clean up before
dispose() - No duplicate observers — klinecharts v10 manages its own
ResizeObserver; the wrapper does not add another
Development
pnpm install
pnpm build # Build library
pnpm dev # Build in watch mode
pnpm typecheck # TypeScript type check
pnpm test # Run vitest unit tests
pnpm test:watch # Run tests in watch mode
# Run the docs site (Starlight) — includes a live, interactive demo
cd docs
pnpm install --ignore-workspace
pnpm devFull documentation lives in docs/ and is published at
https://nemezzizz.github.io/react-klinecharts/.
License
MIT
