npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-klinecharts-ui

v2.0.2

Published

Headless React components for building financial trading terminals with klinecharts

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.

Live Demo · Examples

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

  1. Installation
  2. Concept
  3. KlinechartsUIProvider
  4. Types
  5. Hooks
  6. Utilities
  7. Data & Constants
  8. Custom Indicator Templates
  9. Drawing Overlays
  10. Extensions
  11. State Callbacks
  12. Backend Signals & Notifications
  13. 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 klinecharts

Rendering a chart? react-klinecharts-ui is headless — it does not render the canvas itself. The fastest path is the optional ChartCanvas wrapper, which needs react-klinecharts:

npm install react-klinecharts-ui klinecharts react-klinecharts

You can also initialise the chart yourself with klinecharts.init() and skip react-klinecharts entirely — 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
  • UtilitiescreateDataLoader, 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: dispatch is enhancedDispatch. It synchronously computes the new state by calling the pure reducer directly and immediately invokes onStateChange / 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 presetsuseLayoutManager save/load reproduces each indicator's axis 1:1.

Note: bindIndicatorToNewAxis removes and recreates the indicator (v10 overrideIndicator cannot 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 brush tool (category annotation) 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 useState inside 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 trigger onSettingsChange from 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 orderLine overlay is registered automatically by registerExtensions() (enabled by default). Passing overlays={[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 | null

Returns 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">>): void

Updates 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 calling useMeasure() 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 many useReplay() 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 multiple useAlerts() instances share one list. Note: onAlertTriggered registers a single listener — the last registration wins.

No manual overlay registration. The alertLine overlay template the hook draws with is registered automatically (both by registerExtensions() and lazily inside useAlerts before the first overlay is created) — you don't need to pass it through the provider's overlays prop.

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 (its triggered flag flips to true); 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 range

Return 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