react-klinecharts-ui
v2.0.2
Published
Headless React components for building financial trading terminals with klinecharts
Maintainers
Readme
react-klinecharts-ui — Library Reference
react-klinecharts-ui is a headless React library for building financial trading terminals on top of klinecharts. It provides a state provider, a set of hooks, and overlay templates. No UI components are included — use any UI framework you prefer.
Acknowledgments
Many features in this library — including 11 TradingView-style indicators, 9 drawing overlays, the TA math library, undo/redo, layout manager, and script editor — were ported from the QUANTIX Extended Edition fork of KLineChart-Pro by @dsavenk0. The original fork implements these as a tightly-coupled Vue 3 application; this library re-implements them as headless React hooks following the composable, framework-agnostic architecture.
Table of Contents
- Installation
- Concept
- KlinechartsUIProvider
- Types
- Hooks
- useKlinechartsUI
- useKlinechartsUITheme
- useKlinechartsUILoading
- usePeriods
- useTimezone
- useSymbolSearch
- useIndicators
- useDrawingTools
- useKlinechartsUISettings
- useScreenshot
- useFullscreen
- useOrderLines
- useUndoRedo
- useLayoutManager
- useScriptEditor
- useWatchlist
- useCompare
- useMeasure
- useAnnotations
- useReplay
- useAlerts
- useCrosshair
- useDataExport
- useHotkeys
- useChartAxes
- Utilities
- Data & Constants
- Custom Indicator Templates
- Drawing Overlays
- Extensions
- State Callbacks
- Backend Signals & Notifications
- Full Export List
Installation
npm install react-klinecharts-ui klinecharts
# or with pnpm
pnpm add react-klinecharts-ui klinecharts
# or with yarn
yarn add react-klinecharts-ui klinechartsRendering a chart?
react-klinecharts-uiis headless — it does not render the canvas itself. The fastest path is the optionalChartCanvaswrapper, which needsreact-klinecharts:npm install react-klinecharts-ui klinecharts react-klinechartsYou can also initialise the chart yourself with
klinecharts.init()and skipreact-klinechartsentirely — see Renderer-agnostic.
Concept
The library follows a headless pattern — all UI is written by the consumer. The library is responsible for:
- State management — current symbol, period, theme, indicators, timezone, screenshots
- Datafeed integration — abstract interface for loading historical data and subscribing to real-time updates
- klinecharts overlay management — indicators, drawing tools, order lines
- Utilities —
createDataLoader, overlay templates
All hooks must be called inside <KlinechartsUIProvider>.
Renderer-agnostic
react-klinecharts-ui is headless — it owns state (symbol, period, indicators, alerts, replay, …) and drives a klinecharts Chart instance, but it does not render the canvas. The only bridge between a renderer and the provider is a single dispatch:
dispatch({ type: "SET_CHART", chart });Once the chart instance is registered, every hook (useIndicators, useAlerts, useReplay, …) reads and mutates it via state.chart.*. You can initialise that instance three ways:
1. ChartCanvas (fastest, optional peer react-klinecharts) — the thin wrapper shipped at react-klinecharts-ui/chart wires the <KLineChart> renderer, builds the data loader, forwards symbol/period/theme from provider state, and dispatches SET_CHART for you:
import { KlinechartsUIProvider } from "react-klinecharts-ui";
import { ChartCanvas } from "react-klinecharts-ui/chart";
<KlinechartsUIProvider datafeed={datafeed} defaultSymbol={symbol} defaultTheme="dark">
<ChartCanvas className="h-[500px]" />
</KlinechartsUIProvider>;2. <KLineChart> from react-klinecharts directly — full control over props, at the cost of writing the onReady bridge yourself:
import { useMemo } from "react";
import { KLineChart } from "react-klinecharts";
import { useKlinechartsUI, createDataLoader } from "react-klinecharts-ui";
function ChartView() {
const { state, dispatch, datafeed } = useKlinechartsUI();
const dataLoader = useMemo(() => createDataLoader(datafeed, dispatch), [datafeed, dispatch]);
return (
<KLineChart
dataLoader={dataLoader}
symbol={state.symbol ?? undefined}
period={state.period}
styles={state.theme}
onReady={(chart) => dispatch({ type: "SET_CHART", chart })}
/>
);
}3. Direct klinecharts.init() (no react-klinecharts at all) — for custom lifecycles, SSR/Next.js, or when you want zero extra dependencies:
import { useEffect, useRef } from "react";
import { init, dispose } from "klinecharts";
import { useKlinechartsUI } from "react-klinecharts-ui";
function ChartView() {
const { dispatch, datafeed } = useKlinechartsUI();
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const chart = init(ref.current!);
dispatch({ type: "SET_CHART", chart }); // the bridge
chart!.applyNewData(/* load bars yourself */);
return () => dispose(ref.current!);
}, []);
return <div ref={ref} style={{ height: 500 }} />;
}Whatever route you pick, the hooks work the same — they only care about the Chart instance in the store.
Persistence
By default, user-facing state (alerts, chart settings, the active indicator
set) lives only in memory and is lost on page reload. Pass a storage
option to the provider to hydrate it on mount and write it back on every
change. The adapter mirrors the Web Storage API, so localStorage works out
of the box:
<KlinechartsUIProvider datafeed={datafeed} storage={{}}>
{/* alerts / settings / indicators now survive refresh */}
</KlinechartsUIProvider>storage={{}} uses the defaults: localStorage adapter, the alerts /
settings / indicators namespaces, and a "rkui:" key prefix. You can
override any of them — e.g. plug in a remote or IndexedDB-backed adapter:
import type { StorageAdapter } from "react-klinecharts-ui";
const remoteAdapter: StorageAdapter = {
getItem: (key) => mySyncCache.get(key) ?? null,
setItem: (key, value) => {
mySyncCache.set(key, value);
flushToServer(key, value); // async, fire-and-forget
},
removeItem: (key) => { mySyncCache.delete(key); deleteFromServer(key); },
};
<KlinechartsUIProvider datafeed={datafeed} storage={{ adapter: remoteAdapter }}>Scope. The adapter covers the reducer store today: alerts, settings
(useKlinechartsUISettings), and indicators (the active lists, pane ids,
axis bindings, and visibility). Per-hook useState values — script code
(useScriptEditor), compared symbols (useCompare), watchlist, annotations —
are not yet covered by the adapter and remain in memory. useLayoutManager
(named snapshot presets) is orthogonal: it serializes the whole chart
(indicators + drawings + meta) on demand to its own keys, independent of the
live storage adapter.
The adapter contract is synchronous (matching the Web Storage API). For
async backends, keep a synchronous in-memory cache and flush in the
background — the provider reads/writes through getItem/setItem only.
Workspace & multi-chart
KlinechartsUIProvider owns exactly one chart. To render a grid of charts
that share crosshair / scroll / zoom / symbol / period, wrap several providers
in a WorkspaceProvider and drop a useChartSync bridge inside each:
import {
KlinechartsUIProvider,
WorkspaceProvider,
useChartSync,
useWorkspace,
} from "react-klinecharts-ui";
const cells = [
{ id: "a", symbol: { ticker: "BTCUSDT" }, period: { span: 1, type: "minute", label: "1m" } },
{ id: "b", symbol: { ticker: "ETHUSDT" }, period: { span: 1, type: "minute", label: "1m" } },
];
// Rendered inside each KlinechartsUIProvider — registers its chart with the
// workspace and mirrors viewport events to siblings.
function ChartSyncBridge({ cellId }: { cellId: string }) {
useChartSync({ cellId });
return null;
}
<WorkspaceProvider defaultCells={cells}>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr" }}>
{cells.map((c) => (
<KlinechartsUIProvider key={c.id} datafeed={datafeed} defaultSymbol={c.symbol} defaultPeriod={c.period}>
<ChartSyncBridge cellId={c.id} />
<ChartCanvas />
</KlinechartsUIProvider>
))}
</div>
</WorkspaceProvider>useChartSync mirrors crosshair / scroll / zoom between the registered charts
using only the public klinecharts API (executeAction, scrollToTimestamp,
setBarSpace) — no internal _chartStore. A re-entrancy guard prevents
feedback loops. Per-channel sync can be disabled via the sync prop
({ scroll: false }).
Scope of this foundation. Each cell keeps its own alerts, replay, and drawings (per-provider). Hoisting shared alerts/replay/drawings to the workspace level, plus tabbed layouts and server-persisted workspaces, is planned. Read the multi-chart example for a runnable 2×2 grid.
KlinechartsUIProvider
The root provider. Wraps the application and supplies the context.
import { KlinechartsUIProvider } from "react-klinecharts-ui";
<KlinechartsUIProvider
datafeed={myDatafeed}
defaultSymbol={{ ticker: "BTCUSDT", pricePrecision: 2 }}
defaultTheme="dark"
overlays={[orderLine]}
onSymbolChange={(symbol) => saveToStorage("symbol", symbol)}
>
<App />
</KlinechartsUIProvider>;Props
| Prop | Type | Default | Description |
| ------------------------ | ---------------------------------------------- | ------------------ | ---------------------------------------------------------------- |
| datafeed | Datafeed | — | Required. Datafeed interface implementation |
| defaultSymbol | PartialSymbolInfo | null | Initial trading instrument |
| defaultPeriod | TerminalPeriod | First in periods | Initial timeframe |
| defaultTheme | string | "light" | Initial theme ("light" or "dark") |
| defaultTimezone | string | "Asia/Shanghai" | Initial timezone (IANA) |
| defaultMainIndicators | string[] | ["MA"] | Indicators on the main chart at startup |
| defaultSubIndicators | string[] | ["VOL"] | Indicators on sub-panels at startup |
| defaultLocale | string | "en-US" | Locale passed to klinecharts |
| periods | TerminalPeriod[] | DEFAULT_PERIODS | List of available timeframes |
| styles | DeepPartial<Styles> | — | Custom klinecharts styles (applied when the chart is ready) |
| registerExtensions | boolean | true | Whether to register built-in drawing overlays |
| overlays | OverlayTemplate[] | — | Additional overlay templates (e.g. orderLine, custom overlays) |
| onStateChange | (action, nextState, prevState) => void | — | Called synchronously on every dispatched action |
| onSymbolChange | (symbol) => void | — | Called when the symbol changes |
| onPeriodChange | (period) => void | — | Called when the period changes |
| onThemeChange | (theme) => void | — | Called when the theme changes |
| onTimezoneChange | (timezone) => void | — | Called when the timezone changes |
| onMainIndicatorsChange | (indicators: string[]) => void | — | Called when main indicators change |
| onSubIndicatorsChange | (indicators: Record<string, string>) => void | — | Called when sub-indicators change |
| onSettingsChange | (settings: Record<string, unknown>) => void | — | Called when settings change via useKlinechartsUISettings |
Overlay registration
The provider registers overlays once on mount via useRef — passing an inline array is safe and does not cause re-registration:
// Safe — does not re-register on every render
<KlinechartsUIProvider overlays={[orderLine, myCustomOverlay]}>Types
Datafeed
Data interface implemented by the consumer.
interface Datafeed {
/**
* Search symbols by a query string.
* signal — AbortSignal to cancel the request when a newer query is typed.
*/
searchSymbols(
search: string,
signal?: AbortSignal,
): Promise<PartialSymbolInfo[]>;
/**
* Load historical bars.
* from/to — timestamps in milliseconds.
* When from=0, load the most recent available data.
*/
getHistoryKLineData(
symbol: SymbolInfo,
period: TerminalPeriod,
from: number,
to: number,
): Promise<KLineData[]>;
/**
* Subscribe to real-time updates.
* callback is called for every new bar.
*/
subscribe(
symbol: SymbolInfo,
period: TerminalPeriod,
callback: (data: KLineData) => void,
): void;
/** Unsubscribe from real-time updates. */
unsubscribe(symbol: SymbolInfo, period: TerminalPeriod): void;
}PartialSymbolInfo
Minimal description of a trading instrument.
interface PartialSymbolInfo {
ticker: string; // e.g. "BTCUSDT", "AAPL", "EUR/USD"
pricePrecision?: number; // Decimal places for price display
volumePrecision?: number; // Decimal places for volume display
[key: string]: unknown; // Any additional fields
}KlinechartsUIState
Complete provider state. Accessible via useKlinechartsUI().state.
interface KlinechartsUIState {
chart: Chart | null; // klinecharts Chart instance (null before onReady)
datafeed: Datafeed; // The datafeed passed to the provider
symbol: PartialSymbolInfo | null; // Current symbol
period: TerminalPeriod; // Current timeframe
theme: string; // Current theme: "light" | "dark"
timezone: string; // Current timezone (IANA)
isLoading: boolean; // true while data is loading
locale: string; // klinecharts locale ("en-US")
periods: TerminalPeriod[]; // List of available timeframes
mainIndicators: string[]; // Active main chart indicators
subIndicators: Record<string, string>; // Active sub-indicators: { name → paneId }
indicatorAxes: Record<string, string>; // Custom Y-axis bindings: { indicatorId → yAxisId }
indicatorVisibility: Record<string, boolean>; // Visibility overrides: { indicatorId → false } (sparse)
alerts: Alert[]; // Price alerts (useAlerts) — shared across all consumers
measure: MeasureState; // Measure-tool state (useMeasure): { isActive, fromPoint, result }
replay: ReplayState; // Replay control state (useReplay): { isReplaying, isPaused, speed, barIndex, totalBars }
styles: DeepPartial<Styles> | undefined; // Custom klinecharts styles
screenshotUrl: string | null; // URL of the last screenshot
}KlinechartsUIAction
Union type of all possible actions for dispatch.
type KlinechartsUIAction =
| { type: "SET_CHART"; chart: Chart }
| { type: "SET_SYMBOL"; symbol: PartialSymbolInfo }
| { type: "SET_PERIOD"; period: TerminalPeriod }
| { type: "SET_THEME"; theme: string }
| { type: "SET_TIMEZONE"; timezone: string }
| { type: "SET_LOADING"; isLoading: boolean }
| { type: "SET_MAIN_INDICATORS"; indicators: string[] }
| { type: "SET_SUB_INDICATORS"; indicators: Record<string, string> }
| { type: "SET_INDICATOR_AXES"; axes: Record<string, string> }
| { type: "SET_INDICATOR_VISIBILITY"; visibility: Record<string, boolean> }
| { type: "SET_ALERTS"; alerts: Alert[] }
| { type: "SET_MEASURE"; measure: Partial<MeasureState> }
| { type: "SET_REPLAY"; replay: Partial<ReplayState> }
| { type: "SET_STYLES"; styles: DeepPartial<Styles> | undefined }
| { type: "SET_LOCALE"; locale: string }
| { type: "SET_SCREENSHOT_URL"; url: string | null };Hooks
useKlinechartsUI
The primary hook — returns the full context: state, dispatch, datafeed, and fullscreen ref.
const { state, dispatch, datafeed, onSettingsChange, fullscreenContainerRef } =
useKlinechartsUI();Return value:
interface KlinechartsUIContextValue {
state: KlinechartsUIState;
dispatch: Dispatch<KlinechartsUIAction>; // enhancedDispatch with synchronous callbacks
datafeed: Datafeed;
onSettingsChange?: (settings: Record<string, unknown>) => void;
fullscreenContainerRef: RefObject<HTMLElement | null>;
}Note:
dispatchisenhancedDispatch. It synchronously computes the new state by calling the pure reducer directly and immediately invokesonStateChange/ individual callbacks — without waiting for a React re-render.
useKlinechartsUITheme
Manage the chart theme.
const { theme, setTheme, toggleTheme } = useKlinechartsUITheme();| Field | Type | Description |
| ------------- | ------------------------- | ------------------------------------- |
| theme | string | Current theme: "light" or "dark" |
| setTheme | (theme: string) => void | Set a specific theme |
| toggleTheme | () => void | Toggle between "light" and "dark" |
const { theme, toggleTheme } = useKlinechartsUITheme();
<button onClick={toggleTheme}>
{theme === "dark" ? <SunIcon /> : <MoonIcon />}
</button>;useKlinechartsUILoading
Loading state of chart data.
const { isLoading } = useKlinechartsUILoading();| Field | Type | Description |
| ----------- | --------- | ------------------------------------------------ |
| isLoading | boolean | true while createDataLoader is fetching bars |
const { isLoading } = useKlinechartsUILoading();
{
isLoading && <div className="spinner" />;
}usePeriods
Manage timeframes.
const { periods, activePeriod, setPeriod } = usePeriods();| Field | Type | Description |
| -------------- | ---------------------------------- | --------------------------------- |
| periods | TerminalPeriod[] | Full list of available timeframes |
| activePeriod | TerminalPeriod | Currently selected timeframe |
| setPeriod | (period: TerminalPeriod) => void | Change the timeframe |
TerminalPeriod extends KlinechartsPeriod with a label: string field.
Default timeframes: 1m, 5m, 15m, 1H, 2H, 4H, D, W, M, Y
const { periods, activePeriod, setPeriod } = usePeriods();
<div className="flex gap-1">
{periods.map((p) => (
<button
key={p.label}
onClick={() => setPeriod(p)}
className={activePeriod.label === p.label ? "active" : ""}
>
{p.label}
</button>
))}
</div>;useTimezone
Manage the chart timezone.
const { timezones, activeTimezone, setTimezone } = useTimezone();| Field | Type | Description |
| ---------------- | ---------------------------- | ------------------------- |
| timezones | TimezoneItem[] | Full list of timezones |
| activeTimezone | string | Current IANA timezone key |
| setTimezone | (timezone: string) => void | Change the timezone |
interface TimezoneItem {
key: string; // IANA: "Europe/London", "America/New_York", "UTC"
localeKey: string; // Short name: "london", "new_york", "utc"
}Available timezones:
UTC, Pacific/Honolulu, America/Juneau, America/Los_Angeles, America/Chicago, America/Toronto, America/Sao_Paulo, Europe/London, Europe/Berlin, Asia/Bahrain, Asia/Dubai, Asia/Ashkhabad, Asia/Almaty, Asia/Bangkok, Asia/Shanghai, Asia/Tokyo, Australia/Sydney, Pacific/Norfolk
const { timezones, activeTimezone, setTimezone } = useTimezone();
<select value={activeTimezone} onChange={(e) => setTimezone(e.target.value)}>
{timezones.map((tz) => (
<option key={tz.key} value={tz.key}>
{tz.key}
</option>
))}
</select>;useSymbolSearch
Search and select a trading instrument.
const {
query,
results,
isSearching,
activeSymbol,
setQuery,
selectSymbol,
clearResults,
} = useSymbolSearch(debounceMs);| Parameter | Type | Default | Description |
| ------------ | -------- | ------- | --------------------------------------------- |
| debounceMs | number | 300 | Delay before calling datafeed.searchSymbols |
| Field | Type | Description |
| -------------- | ------------------------------------- | --------------------------------------------- |
| query | string | Current search query |
| results | PartialSymbolInfo[] | Results from the last search |
| isSearching | boolean | true while the request is in flight |
| activeSymbol | PartialSymbolInfo \| null | Currently selected symbol from state.symbol |
| setQuery | (q: string) => void | Update the query (triggers debounced search) |
| selectSymbol | (symbol: PartialSymbolInfo) => void | Select a symbol — dispatches SET_SYMBOL |
| clearResults | () => void | Clear search results |
The hook automatically cancels in-flight requests via AbortController on every new keystroke and on unmount.
const { query, results, isSearching, selectSymbol, setQuery } =
useSymbolSearch(300);
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
/>;
{
isSearching && <Spinner />;
}
{
results.map((sym) => (
<button key={sym.ticker} onClick={() => selectSymbol(sym)}>
{sym.ticker}
</button>
));
}useIndicators
Full indicator management: add/remove, visibility, parameters, move between panes.
const {
mainIndicators,
subIndicators,
activeMainIndicators,
activeSubIndicators,
availableMainIndicators,
availableSubIndicators,
addMainIndicator,
removeMainIndicator,
addSubIndicator,
removeSubIndicator,
toggleMainIndicator,
toggleSubIndicator,
moveToMain,
moveToSub,
setIndicatorVisible,
isIndicatorVisible,
updateIndicatorParams,
getIndicatorParams,
isMainIndicatorActive,
isSubIndicatorActive,
indicatorAxes,
getIndicatorAxis,
indicatorVisibility,
bindIndicatorToNewAxis,
} = useIndicators();Fields
| Field | Type | Description |
| ------------------------- | ------------------------ | ------------------------------------------ |
| mainIndicators | IndicatorInfo[] | All main indicators with isActive + visible flags |
| subIndicators | IndicatorInfo[] | All sub-indicators with isActive + visible flags |
| activeMainIndicators | string[] | Active main indicator names only |
| activeSubIndicators | Record<string, string> | Active sub-indicators: { name → paneId } |
| availableMainIndicators | string[] | Full list from MAIN_INDICATORS |
| availableSubIndicators | string[] | Full list from SUB_INDICATORS |
| indicatorAxes | Record<string, string> | Custom Y-axis bindings: { indicatorId → yAxisId } |
| indicatorVisibility | Record<string, boolean>| Visibility overrides: { indicatorId → false } (sparse — only hidden indicators; absent means visible) |
interface IndicatorInfo {
name: string; // "MA", "MACD", "RSI", etc.
isActive: boolean; // Whether it is currently on the chart
visible: boolean; // Whether it is currently shown (vs hidden); true when inactive
}Methods
| Method | Description |
| --------------------------------------------- | ------------------------------------------------------------- |
| addMainIndicator(name, options?) | Creates the indicator on candle_pane with id main_${name}. Pass { yAxis } to bind it to a secondary axis (see below) |
| removeMainIndicator(name) | Removes the indicator and updates state |
| addSubIndicator(name, options?) | Creates the indicator on a new sub-pane with id sub_${name}. Also accepts { yAxis } |
| removeSubIndicator(name) | Removes the sub-indicator and its pane |
| toggleMainIndicator(name) | add if inactive, remove if active |
| toggleSubIndicator(name) | Same for sub-indicators |
| moveToMain(name) | Moves from sub-pane to candle_pane |
| moveToSub(name) | Moves from candle_pane to a new sub-pane |
| setIndicatorVisible(name, isMain, visible) | Show/hide indicator via chart.overrideIndicator; mirrors the flag into indicatorVisibility |
| isIndicatorVisible(name, isMain) | Reactive read counterpart to setIndicatorVisible; returns true for the default/inactive state |
| updateIndicatorParams(name, paneId, params) | Update calcParams via chart.overrideIndicator |
| getIndicatorParams(name) | Returns [{ label, defaultValue }] or [] if no parameters |
| isMainIndicatorActive(name) | Quick active check |
| isSubIndicatorActive(name) | Quick active check |
| collapseSubIndicator(name) | Collapse a sub-indicator pane to minimal height (30px) |
| expandSubIndicator(name) | Expand a previously collapsed sub-indicator pane |
| isSubIndicatorCollapsed(name) | Whether the given sub-indicator pane is currently collapsed |
| reorderSubIndicator(name, direction) | Reorder a sub-indicator pane "up" or "down" |
| getIndicatorAxis(name, isMain) | Returns the custom yAxisId an indicator is bound to, or undefined for the default axis |
| bindIndicatorToNewAxis(name, isMain, yAxis?)| Rebinds an existing indicator to a different Y-axis (omit yAxis to return it to the default axis) |
Secondary Y-axis binding (multiple Y-axes)
klinecharts v10 supports several independent Y-axes on one pane, so an indicator whose value range differs sharply from price (RSI 0–100, volume, …) can get its own scale instead of distorting the shared price axis or being forced into a separate sub-pane.
// Add RSI on the main pane, on its own left axis (price scale stays intact)
addMainIndicator("RSI", { yAxis: { id: "rsi_axis", position: "left" } });
// Later: move it back to the shared price axis
bindIndicatorToNewAxis("RSI", true);
// Or move an indicator already on the chart onto a dedicated right axis
bindIndicatorToNewAxis("VOL", true, { id: "vol_axis", position: "right" });yAxis is a klinecharts YAxisOverride; the key field is id — indicators sharing the same id share one axis. Useful extras: position ("left" | "right"), name (scale type: "normal" | "percentage" | "log"), inside, and needWidget (set false for an invisible axis — own scale, no labels).
This binding is a persistent property, not a one-shot action. It is tracked in provider state (indicatorAxes, keyed by indicator id) and preserved across:
- undo/redo — toggling an indicator off and back on (
useUndoRedo) restores it on the same axis, not the price axis; - layout presets —
useLayoutManagersave/load reproduces each indicator's axis 1:1.
Note:
bindIndicatorToNewAxisremoves and recreates the indicator (v10overrideIndicatorcannot rebind an axis), preserving calc params, styles and visibility. The rebind action itself is not pushed onto the undo stack.
Available indicators
Main chart (MAIN_INDICATORS): MA, EMA, SMA, BOLL, SAR, BBI
Sub-panes (SUB_INDICATORS): MA, EMA, VOL, MACD, BOLL, KDJ, RSI, BIAS, BRAR, CCI, DMI, CR, PSY, DMA, TRIX, OBV, VR, WR, MTM, EMV, SAR, SMA, ROC, PVT, BBI, AO
Indicators with configurable parameters: SMA, BOLL, SAR, BBI, MACD, KDJ, BRAR, CCI, DMI, CR, PSY, DMA, TRIX, OBV, VR, MTM, EMV, ROC, AO and others.
useDrawingTools
Manage drawing tools (chart overlays).
const {
categories,
activeTool,
magnetMode,
isLocked,
isVisible,
autoRetrigger,
overlays,
selectTool,
clearActiveTool,
setMagnetMode,
toggleLock,
toggleVisibility,
removeAllDrawings,
setAutoRetrigger,
removeDrawing,
setDrawingVisible,
setDrawingLocked,
} = useDrawingTools();| Field/Method | Type | Description |
| ------------------------ | -------------------------------- | ------------------------------------------------------- |
| categories | DrawingCategoryItem[] | Tool categories with nested tools |
| activeTool | string \| null | Name of the last selected tool |
| magnetMode | "normal" \| "weak" \| "strong" | Snap-to-OHLC mode |
| isLocked | boolean | Whether all drawings are locked |
| isVisible | boolean | Whether all drawings are visible |
| autoRetrigger | boolean | Re-arm the tool after finishing a shape (default true) |
| overlays | DrawingOverlayInfo[] | Reactive list of drawings in the drawing_tools group |
| selectTool(name) | — | Start drawing via chart.createOverlay |
| clearActiveTool() | — | Deselect tool (local state only) |
| setMagnetMode(mode) | — | Change magnet mode for all existing and future drawings |
| toggleLock() | — | Toggle lock on all drawings |
| toggleVisibility() | — | Show/hide all drawings |
| removeAllDrawings() | — | Remove all drawings in the drawing_tools group |
| setAutoRetrigger(enabled) | — | Enable/disable auto re-arming |
| removeDrawing(id) | — | Remove a single drawing by id |
| setDrawingVisible(id, visible) | — | Show/hide a single drawing |
| setDrawingLocked(id, locked) | — | Lock/unlock a single drawing |
interface DrawingToolItem {
name: string; // klinecharts overlay name, e.g. "arrow", "fibonacciLine"
localeKey: string; // Localization key
}
interface DrawingCategoryItem {
key: string; // "singleLine" | "moreLine" | "polygon" | "fibonacci" | "wave"
tools: DrawingToolItem[];
}
interface DrawingOverlayInfo {
id: string; // Stable id from klinecharts (chart.getOverlays()[].id)
name: string; // Overlay name, e.g. "segment", "fibonacciLine", "arrow"
paneId: string; // Pane id where the drawing lives
locked: boolean; // Current lock state
visible: boolean; // Current visibility
}Per-drawing management
overlays is a reactive snapshot of the drawings in the drawing_tools group. It updates when a drawing is created (via selectTool + finishing a shape on the canvas), removed, or has its locked/visible properties changed — both through the per-drawing operations above and through the batch operations (toggleLock, toggleVisibility, removeAllDrawings).
Because klinecharts v10 has no overlay change events, the hook also runs a 1s polling fallback so changes made outside the hook (e.g. the user pressing Delete via klinecharts, or undo/redo) are still reflected.
// Build an Object Tree panel from `overlays`
const { overlays, removeDrawing, setDrawingVisible, setDrawingLocked } = useDrawingTools();
// overlays.map((o) => (
// <Row
// key={o.id}
// label={drawingLabel(o.name)} // "segment" -> "segment" locale key
// visible={o.visible}
// locked={o.locked}
// onToggleVis={() => setDrawingVisible(o.id, !o.visible)}
// onDel={() => removeDrawing(o.id)}
// />
// ));drawingLabel(name) is an exported helper that maps a klinecharts overlay name to its localeKey using DRAWING_CATEGORIES (falls back to the name itself when the tool is unknown), so consumers don't have to duplicate the category table.
Categories and tools:
| Category (key) | Tools |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| singleLine | horizontalStraightLine, horizontalRayLine, horizontalSegment, verticalStraightLine, verticalRayLine, verticalSegment, straightLine, rayLine, segment, arrow, priceLine |
| moreLine | priceChannelLine, parallelStraightLine |
| polygon | circle, rect, parallelogram, triangle |
| fibonacci | fibonacciLine, fibonacciSegment, fibonacciCircle, fibonacciSpiral, fibonacciSpeedResistanceFan, fibonacciExtension, gannBox |
| wave | xabcd, abcd, threeWaves, fiveWaves, eightWaves, anyWaves |
| annotation | brush |
Freehand drawing. The
brushtool (categoryannotation) uses klinecharts' continuous (freehand) drawing mode — hold and drag to sketch. It is a built-in overlay that requires klinecharts 10.0.0 (stable) or later to render.
useKlinechartsUISettings
Manage chart appearance: candle type, colors, price marks, axes, grid, crosshair, tooltips.
const settings = useKlinechartsUISettings();State
| Field | Type | Default | Description |
| ------------------------ | --------------- | ---------------- | ------------------------- |
| candleType | string | "candle_solid" | Candle display type |
| candleUpColor | string | "#2DC08E" | Bullish candle color |
| candleDownColor | string | "#F92855" | Bearish candle color |
| compareRule | CompareRule | "current_open" | Baseline rule for compared symbols |
| showLastPrice | boolean | true | Last price mark on Y-axis |
| showLastPriceLine | boolean | true | Last price horizontal line |
| showHighPrice | boolean | true | High price mark |
| showLowPrice | boolean | true | Low price mark |
| showIndicatorLastValue | boolean | true | Indicator last value mark |
| priceAxisType | PriceAxisType | "normal" | Y-axis scale type |
| yAxisPosition | YAxisPosition | "right" | Y-axis side ("left" \| "right") |
| yAxisInside | boolean | false | Draw the Y-axis inside the pane |
| reverseCoordinate | boolean | false | Invert Y-axis |
| showTimeAxis | boolean | true | Show X-axis |
| showGrid | boolean | true | Show grid |
| showCrosshair | boolean | true | Show crosshair |
| showCandleTooltip | boolean | true | OHLCV tooltip |
| showIndicatorTooltip | boolean | true | Indicator tooltip |
| tooltipShowRule | TooltipShowRule| "always" | When to show tooltips |
Candle types: candle_solid, candle_stroke, candle_up_stroke, candle_down_stroke, ohlc, area
Price axis types: "normal", "percentage", "log"
Extra fields
| Field | Type | Description |
| ------------------ | ----------------------------------------------- | ----------------------------------------------------- |
| candleTypes | CandleTypeItem[] | List of { key, localeKey } for rendering a selector |
| priceAxisTypes | { key: PriceAxisType; localeKey: string }[] | List for rendering a selector |
| yAxisPositions | { key: YAxisPosition; localeKey: string }[] | List for rendering a selector |
| compareRules | { key: CompareRule; localeKey: string }[] | List for rendering a selector |
| tooltipShowRules | { key: TooltipShowRule; localeKey: string }[] | List for rendering a selector |
Setters
Each field has a corresponding setter: setCandleType, setCandleUpColor, setCandleDownColor, setCompareRule, setShowLastPrice, setShowLastPriceLine, setShowHighPrice, setShowLowPrice, setShowIndicatorLastValue, setPriceAxisType, setYAxisPosition, setYAxisInside, setReverseCoordinate, setShowTimeAxis, setShowGrid, setShowCrosshair, setShowCandleTooltip, setShowIndicatorTooltip, setTooltipShowRule.
All setters immediately apply changes via chart.setStyles(...).
| Method | Description |
| ------------------- | ----------------------------------------------------------- |
| resetToDefaults() | Reset all settings to defaults via chart.setStyles(theme) |
Important: Settings are stored in local
useStateinside the hook — they are not part of the provider's reducer state. The hook must be called unconditionally (not only when a dialog is open) to preserve settings across dialog open/close cycles. Changes triggeronSettingsChangefrom the provider.
useScreenshot
Capture and download a chart screenshot.
const { screenshotUrl, capture, download, clear } = useScreenshot();| Field/Method | Type | Description |
| --------------------- | ----------------------------- | ------------------------------------------------------ |
| screenshotUrl | string \| null | JPEG data URL of the last screenshot |
| capture() | () => void | Capture the current chart state |
| download(filename?) | (filename?: string) => void | Download as a file (default: "chart-screenshot.jpg") |
| clear() | () => void | Clear screenshotUrl from state |
Screenshot is created via chart.getConvertPictureUrl(true, "jpeg", bgColor). Background depends on the current theme: #151517 for dark, #ffffff for light.
const { screenshotUrl, capture, download, clear } = useScreenshot();
<button onClick={capture}>Capture</button>;
{
screenshotUrl && (
<>
<img src={screenshotUrl} alt="chart" />
<button onClick={() => download()}>Download</button>
<button onClick={clear}>Close</button>
</>
);
}useFullscreen
Toggle fullscreen mode. Uses fullscreenContainerRef from the provider.
const { isFullscreen, toggle, enter, exit, containerRef } = useFullscreen();| Field/Method | Type | Description |
| -------------- | -------------------------------- | ------------------------------ |
| isFullscreen | boolean | Current fullscreen state |
| toggle() | () => void | Toggle |
| enter() | () => void | Enter fullscreen |
| exit() | () => void | Exit fullscreen |
| containerRef | RefObject<HTMLElement \| null> | The same ref from the provider |
Supports cross-browser vendor prefixes (webkit, ms).
Important: containerRef must be assigned to the container element that should occupy the full screen (typically the root layout element):
const { containerRef, toggle, isFullscreen } = useFullscreen();
<div ref={containerRef as React.RefObject<HTMLDivElement>}>
<button onClick={toggle}>{isFullscreen ? "Exit" : "Fullscreen"}</button>
<ChartView />
</div>;useOrderLines
Create and manage horizontal price level lines (order lines).
No setup required. The
orderLineoverlay is registered automatically byregisterExtensions()(enabled by default). Passingoverlays={[orderLine]}to the provider still works and is harmless, but is no longer necessary.
const {
createOrderLine,
updateOrderLine,
removeOrderLine,
removeAllOrderLines,
} = useOrderLines();createOrderLine
createOrderLine(options: OrderLineOptions): string | nullReturns the id of the created line, or null if the chart is not ready.
interface OrderLineOptions extends OrderLineExtendData {
id?: string; // Auto-generated if omitted
price: number; // Price level
draggable?: boolean; // Allow drag to change price. Default: false
onPriceChange?: (price: number) => void; // Called when drag ends
}All OrderLineExtendData fields (see orderLine extension) are accepted directly — they flow through as overlay extendData.
updateOrderLine
updateOrderLine(id: string, options: Partial<Omit<OrderLineOptions, "id">>): voidUpdates an existing line. Only pass the fields you want to change.
removeOrderLine / removeAllOrderLines
removeOrderLine(id: string): void
removeAllOrderLines(): void // Removes all overlays with name="orderLine"const { createOrderLine, updateOrderLine, removeOrderLine } = useOrderLines();
const id = createOrderLine({
price: 45000,
color: "#ff9900",
text: "Target",
line: { style: "dashed" },
mark: { bg: "#ff9900", color: "#fff" },
draggable: true,
onPriceChange: (newPrice) => console.log("Moved to:", newPrice),
});
updateOrderLine(id!, { color: "#00ff00" });
removeOrderLine(id!);useUndoRedo
Undo/redo history for drawing overlays and indicator toggles. Automatically connected to useDrawingTools and useIndicators via a shared context ref — actions are recorded without manual wiring.
Keyboard shortcuts: Ctrl+Z (undo), Ctrl+Y / Ctrl+Shift+Z (redo).
import { useUndoRedo } from "react-klinecharts-ui";
const { canUndo, canRedo, undo, redo, pushAction, clear } = useUndoRedo();Return type: UseUndoRedoReturn
| Property | Type | Description |
|----------|------|-------------|
| canUndo | boolean | Whether there are actions to undo |
| canRedo | boolean | Whether there are actions to redo |
| undo | () => void | Undo the last action |
| redo | () => void | Redo the last undone action |
| pushAction | (action: UndoRedoAction) => void | Push a new action onto the undo stack (clears redo) |
| clear | () => void | Clear all undo/redo history |
Action types
| Type | Trigger | Undo behaviour | Redo behaviour |
|------|---------|----------------|----------------|
| overlay_added | User completes a drawing | Removes the overlay | Re-creates the overlay |
| overlays_removed | removeAllDrawings() | Restores all removed overlays | Re-removes them |
| indicator_toggled | Add/remove indicator | Reverses the toggle | Re-applies the toggle |
Cross-hook communication
useUndoRedo registers a pushAction callback on undoRedoListenerRef (shared via provider context). When useDrawingTools finishes a drawing or useIndicators toggles an indicator, they call the ref to record the action — no prop drilling required.
useLayoutManager
Save, load, rename, and delete named chart layouts via localStorage. Captures indicators, drawings, symbol, and period. Optional auto-save with 5-second debounce.
import { useLayoutManager } from "react-klinecharts-ui";
const {
layouts,
saveLayout,
loadLayout,
deleteLayout,
renameLayout,
refreshLayouts,
autoSaveEnabled,
setAutoSaveEnabled,
} = useLayoutManager();Return type: UseLayoutManagerReturn
| Property | Type | Description |
|----------|------|-------------|
| layouts | LayoutEntry[] | List of saved layout entries |
| saveLayout | (name: string) => string \| null | Save current chart state; returns layout ID |
| loadLayout | (id: string) => boolean | Load and apply a layout by ID |
| deleteLayout | (id: string) => void | Delete a layout |
| renameLayout | (id: string, name: string) => boolean | Rename a layout |
| refreshLayouts | () => void | Refresh the list from localStorage |
| autoSaveEnabled | boolean | Whether auto-save is enabled |
| setAutoSaveEnabled | (enabled: boolean) => void | Toggle auto-save |
LayoutEntry
interface LayoutEntry {
id: string;
name: string;
symbol: string;
period: string;
timestamp: number;
lastModified: number;
state: ChartLayoutState;
}ChartLayoutState
interface ChartLayoutState {
version: string;
meta: { symbol: string; period: string; timestamp: number; lastModified: number };
indicators: Array<{ paneId: string; name: string; calcParams: any[]; visible: boolean }>;
drawings: Array<{ name: string; points: any[]; styles?: any; extendData?: any }>;
}useScriptEditor
Pine Script-style custom indicator editor. Users write plain JavaScript function bodies that receive TA, dataList (array of KLineData), and params (parsed from a comma-separated string). The script must return an array of objects — one per candle, each key becomes a chart series.
Scripts execute inside a sandboxed new Function() with dangerous globals shadowed: fetch, XMLHttpRequest, WebSocket, Worker, SharedWorker, importScripts, self, caches, indexedDB.
import { useScriptEditor } from "react-klinecharts-ui";
const {
code, setCode,
scriptName, setScriptName,
params, setParams,
placement, setPlacement,
error, status, isRunning, hasActiveScript,
runScript, removeScript, resetCode,
exportScript, importScript,
defaultScript,
} = useScriptEditor();Return type: UseScriptEditorReturn
| Property | Type | Description |
|----------|------|-------------|
| code | string | Current script source code |
| setCode | (code: string) => void | Update the source code |
| scriptName | string | Display name of the script |
| setScriptName | (name: string) => void | Update the name |
| params | string | Comma-separated numeric params (e.g. "14, 26, 9") |
| setParams | (params: string) => void | Update params |
| placement | ScriptPlacement | "main" or "sub" |
| setPlacement | (p: ScriptPlacement) => void | Set placement |
| error | string | Last error message (empty = no error) |
| status | string | Last status message |
| isRunning | boolean | Whether the script is currently executing |
| hasActiveScript | boolean | Whether a script indicator is on the chart |
| runScript | () => void | Execute the script and register the indicator |
| removeScript | () => void | Remove the current script indicator from the chart |
| resetCode | () => void | Reset code to the default template |
| exportScript | () => void | Download the code as a .js file |
| importScript | (file: File) => void | Load a script from a file |
| defaultScript | string | The default template code |
Example script
// Available: TA, dataList, params
const period = params[0] ?? 14;
const closes = dataList.map(d => d.close);
const highs = dataList.map(d => d.high);
const lows = dataList.map(d => d.low);
const rsi = TA.rsi(closes, period);
const boll = TA.bollinger(closes, period, 2);
// Return one object per candle — each key = one line on the chart
return rsi.map((v, i) => ({
rsi: v,
upper: boll.upper[i],
mid: boll.mid[i],
lower: boll.lower[i],
}));useWatchlist
Manage a list of tracked symbols with live price updates from your datafeed.
import { useWatchlist } from "react-klinecharts-ui";
const {
items,
addSymbol,
removeSymbol,
switchSymbol,
activeSymbol,
} = useWatchlist();Return type: UseWatchlistReturn
| Property | Type | Description |
|----------|------|-------------|
| items | WatchlistItem[] | Array of tracked symbols with price data |
| addSymbol | (ticker: string) => void | Add a symbol to the watchlist |
| removeSymbol | (ticker: string) => void | Remove a symbol from the watchlist |
| switchSymbol | (ticker: string) => void | Change the chart to display a symbol |
| activeSymbol | string \| null | Currently displayed symbol ticker |
WatchlistItem
| Property | Type | Description |
|----------|------|-------------|
| ticker | string | Symbol identifier |
| lastPrice | number \| null | Last traded price |
| change | number \| null | Absolute price change |
| changePercent | number \| null | 24h percentage change |
useCompare
Compare multiple symbols on the same chart with individual colors and visibility toggle.
import { useCompare } from "react-klinecharts-ui";
const {
symbols,
addSymbol,
removeSymbol,
toggleSymbol,
clearAll,
} = useCompare();Return type: UseCompareReturn
| Property | Type | Description |
|----------|------|-------------|
| symbols | CompareSymbol[] | Array of comparison symbols with metadata |
| addSymbol | (ticker: string, color?: string) => Promise<void> | Add a symbol to compare (optional line color) |
| removeSymbol | (ticker: string) => void | Remove a comparison symbol |
| toggleSymbol | (ticker: string) => void | Toggle visibility of a symbol |
| clearAll | () => void | Remove all comparison symbols |
CompareSymbol
| Property | Type | Description |
|----------|------|-------------|
| ticker | string | Symbol identifier |
| visible | boolean | Whether the symbol is currently visible on chart |
| color | string | Hex color code for the symbol's line |
useMeasure
Measure price changes, percentage swings, bar count, and time intervals between two points on the chart.
Multi-instance safe. State lives in the shared provider store (
state.measure), so callinguseMeasure()in several components (e.g. a toolbar toggle and a separate result panel) keeps them in sync — no need to hoist a single instance.
import { useMeasure } from "react-klinecharts-ui";
const {
isActive,
startMeasure,
cancelMeasure,
result,
clearResult,
fromPoint,
} = useMeasure();Return type: UseMeasureReturn
| Property | Type | Description |
|----------|------|-------------|
| isActive | boolean | Whether measurement mode is enabled |
| startMeasure | () => void | Enter measurement mode (click two points) |
| cancelMeasure | () => void | Exit measurement mode |
| result | MeasureResult \| null | Measurement data (null if not measured yet) |
| clearResult | () => void | Clear the current measurement result |
| fromPoint | MeasurePoint \| null | The first picked point while measuring (null when inactive) |
MeasureResult
| Property | Type | Description |
|----------|------|-------------|
| priceDiff | number | Absolute price difference |
| pricePercent | number | Percentage change |
| bars | number | Number of bars between points |
| timeDiff | number | Time difference in milliseconds |
useAnnotations
Add text annotations at specific price levels and timestamps with optional colors.
import { useAnnotations } from "react-klinecharts-ui";
const {
annotations,
addAnnotation,
removeAnnotation,
updateAnnotation,
clearAnnotations,
} = useAnnotations();Return type: UseAnnotationsReturn
| Property | Type | Description |
|----------|------|-------------|
| annotations | Annotation[] | Array of all annotations |
| addAnnotation | (text, price, timestamp, color?) => string | Add annotation; returns ID |
| removeAnnotation | (id: string) => void | Remove annotation by ID |
| updateAnnotation | (id, updates) => void | Update text or color |
| clearAnnotations | () => void | Remove all annotations |
Annotation
| Property | Type | Description |
|----------|------|-------------|
| id | string | Unique identifier |
| text | string | Annotation text |
| price | number | Price level |
| timestamp | number | Candle timestamp |
| color | string \| undefined | Optional hex color |
useReplay
Replay historical candles at various speeds with play/pause/step controls and progress tracking.
Multi-instance safe. Control state lives in the shared store (
state.replay) and the playback timer + data buffers are owned by the provider, so there is exactly one replay session no matter how manyuseReplay()instances are mounted — start in one component and step in another, and they drive the same session.
import { useReplay } from "react-klinecharts-ui";
const {
isReplaying,
isPaused,
speed,
barIndex,
totalBars,
startReplay,
stopReplay,
togglePause,
stepForward,
stepBackward,
seekTo,
setSpeed,
} = useReplay();Return type: UseReplayReturn
| Property | Type | Description |
|----------|------|-------------|
| isReplaying | boolean | Whether a replay session is active |
| isPaused | boolean | Whether the replay is currently paused |
| speed | ReplaySpeed | Current playback speed multiplier (1 \| 2 \| 5 \| 10) |
| barIndex | number | Current bar index in the replay |
| totalBars | number | Total bars in the saved dataset |
| startReplay | () => void | Start replaying from the beginning |
| stopReplay | () => void | Stop replay and restore the original data |
| togglePause | () => void | Toggle play/pause |
| stepForward | () => void | Advance one bar while paused |
| stepBackward | () => void | Go back one bar while paused |
| seekTo | (index: number) => void | Seek to a specific bar index (pauses playback) |
| setSpeed | (speed: ReplaySpeed) => void | Change the playback speed |
useAlerts
Client-side price alerts. Draws a labelled locked horizontal line (price tag on the Y-axis + a bell-marked caption above the line) on the chart for each alert and polls the latest candle once per second, firing a callback when the close price crosses the alert level. This is the primary hook for reacting to price events — e.g. forwarding a buy/sell signal to your backend or triggering a push notification (see Backend Signals & Notifications).
Multi-instance safe. The alert list lives in the shared store (
state.alerts) and the crossing poller is owned by the provider (one poller, active only while alerts exist), so multipleuseAlerts()instances share one list. Note:onAlertTriggeredregisters a single listener — the last registration wins.
No manual overlay registration. The
alertLineoverlay template the hook draws with is registered automatically (both byregisterExtensions()and lazily insideuseAlertsbefore the first overlay is created) — you don't need to pass it through the provider'soverlaysprop.
import { useAlerts } from "react-klinecharts-ui";
const {
alerts,
addAlert,
removeAlert,
clearAlerts,
onAlertTriggered,
} = useAlerts();
// Default: orange dashed line, bell + price/message caption.
const id = addAlert(65000, "crossing_up", "BTC broke 65k");
// Customize the look via the optional 4th argument (AlertLineExtendData).
addAlert(70000, "crossing_up", "Take profit", {
color: "#e91e63",
showBell: true,
});
onAlertTriggered((alert) => {
console.log("Alert fired:", alert.message, alert.price);
});Return type: UseAlertsReturn
| Property | Type | Description |
|----------|------|-------------|
| alerts | Alert[] | Current alerts (active and triggered) |
| addAlert | (price: number, condition: AlertCondition, message?: string, extendData?: AlertLineExtendData) => string | Create an alert at a price level; returns its id. The optional extendData customizes the line/label look |
| removeAlert | (id: string) => void | Remove a single alert and its chart line |
| clearAlerts | () => void | Remove all alerts |
| onAlertTriggered | (callback: (alert: Alert) => void) => void | Register a callback fired once when an alert's condition is met |
Types
type AlertCondition = "crossing_up" | "crossing_down" | "crossing";
interface Alert {
id: string;
price: number;
condition: AlertCondition;
message?: string;
triggered: boolean;
/** Visual style of the alert line; persisted so it survives undo/redo & layout presets. */
extendData?: AlertLineExtendData;
}
interface AlertLineExtendData {
/** Primary color for the line, the Y-axis mark bg, and label fallback. Default: "#ff9800" */
color?: string;
/** Caption above the line. Defaults to `message ?? formatted price` (symbol precision). */
text?: string;
/** Line style overrides (style / width / dashedValue). Default: dashed. */
line?: OrderLineLineStyle;
/** Y-axis price mark style overrides. */
mark?: OrderLineMarkStyle;
/** Caption text style overrides. */
label?: OrderLineLabelStyle;
/** Show a 🔔 marker before the caption. Default: true */
showBell?: boolean;
}The line / mark / label style types are shared with useOrderLines (OrderLineLineStyle, OrderLineMarkStyle, OrderLineLabelStyle).
| Condition | Fires when |
|-----------|------------|
| crossing_up | Previous close < price and current close >= price |
| crossing_down | Previous close > price and current close <= price |
| crossing | Either direction |
Detection is based on the latest candle's close, polled every second from
chart.getDataList(). An alert fires at most once (itstriggeredflag flips totrue); recreate it to re-arm.
useCrosshair
Tracks the OHLCV data of the bar currently under the crosshair. Returns null when the cursor is off-chart. Updates are throttled with requestAnimationFrame, making it suitable for driving a live data panel / legend that follows the cursor.
import { useCrosshair } from "react-klinecharts-ui";
const { barData } = useCrosshair();
// barData is null until the cursor is over a candle
if (barData) {
console.log(barData.close, barData.changePercent);
}Return type: UseCrosshairReturn
| Property | Type | Description |
|----------|------|-------------|
| barData | CrosshairBarData \| null | OHLCV of the hovered bar, or null when off-chart |
CrosshairBarData
| Property | Type | Description |
|----------|------|-------------|
| open | number | Open price |
| high | number | High price |
| low | number | Low price |
| close | number | Close price |
| volume | number | Volume |
| timestamp | number | Bar timestamp (ms) |
| change | number | close - open, rounded to the symbol's price precision |
| changePercent | number | Percent change relative to open, 2 decimals |
useDataExport
Export chart candle data to a downloaded file in CSV or JSON format. Columns: Date (ISO), Open, High, Low, Close, Volume. The file is named <ticker>_<YYYY-MM-DD>.<format>.
import { useDataExport } from "react-klinecharts-ui";
const { exportAll, exportVisible } = useDataExport();
exportAll("csv"); // every loaded bar
exportVisible("json"); // only the currently visible rangeReturn type: UseDataExportReturn
| Property | Type | Description |
|----------|------|-------------|
| exportAll | (format: ExportFormat) => void | Download all loaded candles |
| exportVisible | (format: ExportFormat) => void | Download only the visible range (falls back to all bars if the range is unavailable) |
type ExportFormat = "csv" | "json";No-op when the chart is not ready or holds no data.
useHotkeys
Keyboard shortcuts (klinecharts v10, requires klinecharts 10.0.0+). Register custom hotkeys globally and toggle hotkey handling per chart. The action callback receives the chart instance, the keyboard event, the matched key, and the hotkey template.
import { useHotkeys } from "react-klinecharts-ui";
const { registerHotkey, setHotkeysEnabled, suppo