Generated banner for Lightweight Charts React Components
Generated logo for Lightweight Charts React Components

Lightweight Charts React Components

GitHubOfficialCreated by ukorvlDistributed by GitHub

  • Skill
  • Tool integration
  • Software development
  • MIT
  • No issues found

From the author

lightweight-charts-react-components recipes for TradingView lightweight-charts in React. Candlestick, line, and area series; volume and indicator panes; realtime WebSocket updates; infinite history on scroll; crosshair OHLC legends and tooltips; trade markers and price lines; synchronized charts; numeric options and yield-curve axes. Use when adding or fixing a financial or trading chart in a React app, or when the user mentions lightweight-charts, TradingView charts in React, or this package.
— the description by ukorvl

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a set of React components and recipes for integrating TradingView's lightweight-charts library into React applications. It simplifies the management of chart lifecycles, series creation, and data updates. The library supports various chart types including candlestick, line, and area series, along with advanced features like real-time WebSocket updates, synchronized charts, and custom tooltips. It is designed to handle complex financial data requirements such as infinite history scrolling, indicator panes, and trade markers while maintaining React's declarative programming model.

What it does

  • Provides React components for rendering TradingView lightweight-charts.
  • Manages chart and series lifecycle, including creation and cleanup.
  • Supports real-time data updates via WebSocket integration.
  • Enables complex UI features like crosshair legends, tooltips, and trade markers.
  • Facilitates synchronized multi-chart layouts and custom axis configurations.
  • Handles infinite history loading and viewport management.

When to use it

  • When building financial or trading dashboards in a React application.
  • When you need to integrate TradingView lightweight-charts with React state.
  • When implementing features like real-time price updates or historical data pagination.
  • When creating complex chart layouts with indicators, volume panes, or synchronized crosshairs.

Advantages

  • Declarative component-based API for chart configuration.
  • Automatic management of chart lifecycle and DOM cleanup.
  • Built-in recipes for common financial charting patterns.
  • Flexible data handling for both static datasets and live streaming updates.

Usage examples

“How do I create a basic line chart using lightweight-charts-react-components?”
The agent provides a code snippet using the Chart and LineSeries components, demonstrating how to pass data and configure container dimensions.
“How can I implement a tooltip that shows OHLC values on hover?”
The agent provides a recipe using onCrosshairMove to track cursor position and map it to the series data, rendering a custom React tooltip.
“How do I handle infinite scrolling for historical data?”
The agent provides a pattern for using a ref-based data store and a loadOlder callback to prepend data to the chart without losing the user's current view.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/github/lightweight-charts-react-components/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip lightweight-charts-react-components.zip -d .agents/skills

Documentation by ukorvl

lightweight-charts-react-components guide

Quick Start

Let the components manage chart and series creation and cleanup. Import components and ref types from lightweight-charts-react-components; import native data, option, and event types from lightweight-charts.

  1. Check versions against the compatibility table below. Read declared ranges from the app's package.json, then the installed versions from the version field of node_modules/<package>/package.json for lightweight-charts-react-components, lightweight-charts, react, and react-dom. If the library is not installed, follow Installation. Ensure chart rendering runs in the browser, within the app's client boundary.

  2. For a basic static chart, start from the minimal chart below. Otherwise, read the reference matching the requested behavior. Adapt its feed and UI; preserve its data contract, component nesting, and API readiness handling.

  3. Choose one data owner: pass the complete dataset through data for React-owned updates, or use reactive={false} and the series API for frequent ticks.

Installation

Install the wrapper together with its lightweight-charts peer dependency, using the project's package manager. React and React DOM must already be installed.

npm install lightweight-charts-react-components lightweight-charts
Minimal chart
import type { LineData, UTCTimestamp } from "lightweight-charts";
import {
  Chart,
  LineSeries,
  TimeScale,
  TimeScaleFitContentTrigger,
} from "lightweight-charts-react-components";

// Data must be sorted ascending by time with unique times (UTC seconds here).
export function SimpleLineChart({ data }: { data: LineData<UTCTimestamp>[] }) {
  return (
    // autoSize follows the container, which needs a nonzero height.
    <Chart
      options={{ autoSize: true }}
      containerProps={{ style: { height: 300, width: "100%" } }}
    >
      <LineSeries data={data} />
      <TimeScale>
        <TimeScaleFitContentTrigger deps={[]} />
      </TimeScale>
    </Chart>
  );
}

Examples and snippets (reference files)

Read the reference matching the user's outcome. Each contains a complete TypeScript recipe, data and integration contracts, reasons for the architecture, failure modes, and acceptance checks. Combine references when a task spans several outcomes; do not load every reference for a simple chart.

User requestReference
WebSocket candles, updating the current bar, stale history, excessive chart rendersMarket data and live updates
Older history on scroll, viewport jumps, symbol/interval changes, late API responsesHistory and range selection
Candles plus volume, moving averages, oscillator panes, independent price scalesPrice, volume, and indicators
OHLC legend, hover details, missing data, tooltip positioningHover legends and tooltips
Executions and signals, stop/target levels, click-to-place price linesTrade markers and price levels
Compare assets with different prices, fixed-baseline returns, toggle comparisonsPerformance comparison
Separate charts that share scrolling, zooming, and a crosshairSynchronized charts
Trading-session shading, pane backgrounds, custom drawing that follows zoomSession overlays and primitives
Options strikes, yield maturities, choosing a numeric or custom horizontal axisNumeric axes and chart types

If no reference matches the request, tell the user that the skill has no recipe for it. Then build the solution from the public components and the upstream lightweight-charts API, applying the Quick Start rules and the edge cases below.

Skill compatibility

The recipes are verified against the reference versions below. These are the tested baseline, not the latest available releases.

If an installed version differs from the reference version, compare it with the compatibility range. Inside the range, recipes apply as written. Outside it, tell the user about the mismatch before writing code, because breaking API changes can affect the recipes, and verify every API the recipe uses against the installed package.

Dependency or environmentReference versionCompatibility range and checks
lightweight-charts-react-components2.6.1Recipe target: >=2.6.1 <3. Other versions require checking installed exports, chart API refs, and reactive data behavior before adapting a recipe.
lightweight-charts5.2.1Declared peer: >=5.0.8 <6.
React and React DOM19.2.6Declared peers: >=18.2 <20. Keep react and react-dom on matching versions and use the application's existing React instance.
Node.js—Package engines: >=18.14.0. The app's build tools can require a newer version.
Module systemESMESM import entry only; there is no CommonJS require entry.
RenderingBrowserCharts need the DOM and canvas. Render them on the client, never during server rendering.

Common edge cases

  • Chart sizing: Put DOM styles on containerProps and give the chart a nonzero height.

  • Required ancestors: Headless chart children need a chart wrapper ancestor. Markers, PriceLine, and SeriesPrimitive belong inside their series; PriceScale, Watermark, and PanePrimitive require a Pane; TimeScaleFitContentTrigger requires a TimeScale.

  • API refs and readiness: Use ref.current?.api() for the native API and containerRef for the div. For Chart, use ChartApiRef<Time, IChartApi>. .api() can initially return null; follow the recipe's readiness step before imperative setup.

  • Viewport resets: To preserve scroll/zoom, keep the chart's key stable and live/history updates out of fit-trigger dependencies. Fit on initial load or a deliberate reset. See range handling.

  • Data updates: Use data for React-owned updates, or reactive={false} and the series API when per-tick React renders are measurably costly. Avoid mixing both. Reactive data is always the complete dataset. With wrapper 2.6.1 and Lightweight Charts 5.2.1, series.data() reconstructs candle and line objects; the wrapper's earlier-item reference comparison therefore sends multi-bar tail updates through setData(), even when React keeps earlier references stable. Keep data immutable, but use the chart-owned reactive={false} recipe and explicit series.update(bar) when incremental writes are required. See live updates.

Source

Adapted from ukorvl/lightweight-charts-react-components at commit 0368191127568e48aef6f7bda2ff3900e8e24756. Original author: ukorvl. The MIT license and all nine reference recipes are retained. Local corrections in live updates reject malformed timestamps and explain the tested versions' reactive-update limitation; session overlays clarifies the primitive update callback. The other seven references and MIT notice are unchanged. This catalog copy adds source attribution and operational boundaries; it does not imply TradingView endorsement.

Recipes generate application code and can change dependencies. Follow the user's requested scope and the host's approval policy. Feed access belongs to the app's separately authorized adapter; keep credentials out of client code. Trade markers are visual annotations, not order execution or server-side alerts. Use synthetic data for local checks and report browser/feed behavior that remains untested.

Files

references/hover-legends-and-tooltips.md

Hover legends and tooltips

Use this for “show OHLC under the cursor,” a persistent latest-bar legend, or a floating details box. The chart renders a canvas; the wrapper supplies event handlers but no tooltip or legend UI. Keep the HTML details alongside the chart in a positioned application container.

Architecture choices

  • Use onCrosshairMove on Chart; the wrapper owns subscription and cleanup. Do not also call subscribeCrosshairMove() for the same handler.

  • Look up param.seriesData by the native series API returned by seriesRef.current.api(). The map is not keyed by wrapper refs or string IDs.

  • The map can omit a series at a given time. Check presence and the appropriate shape (close for candles, value for lines/histograms) before reading values.

  • Keep selection by time and read current data from the application snapshot. Updating the currently hovered candle then updates the legend even when the pointer stays still. Comparing only timestamps would leave stale OHLC values.

  • Ignore identical selection/position updates. Native option/data updates can emit crosshair events; always creating new React state can feed back into another options update and cause a render loop. Selection equality is safe here because displayed OHLC comes from current data, not cached event values.

  • param.point is local to the chart pane, not the viewport. This recipe is for one pane; add each pane's DOM offset for tooltips over a multi-pane chart.

Recipe: live OHLC legend and clamped tooltip

data is normalized, ascending, unique UTC-second candles; the initial snapshot is ready before mounting. The application owns live updates through the complete array. Copy this as one component module. The details are React text, so symbol labels and values are not interpolated into innerHTML.

import { useCallback, useMemo, useRef, useState } from "react";
import type { CandlestickData, MouseEventParams, UTCTimestamp } from "lightweight-charts";
import {
  CandlestickSeries,
  Chart,
  TimeScale,
  TimeScaleFitContentTrigger,
  type SeriesApiRef,
} from "lightweight-charts-react-components";

type Hover = { time: UTCTimestamp; x: number; y: number };
const tooltipWidth = 190;
const tooltipHeight = 96;
const chartOptions = { autoSize: true, timeScale: { timeVisible: true } };

export function CandleDetails({
  symbol,
  data,
}: {
  symbol: string;
  data: CandlestickData<UTCTimestamp>[];
}) {
  const seriesRef = useRef<SeriesApiRef<"Candlestick">>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const [hover, setHover] = useState<Hover | null>(null);
  const byTime = useMemo(() => new Map(data.map(bar => [bar.time, bar])), [data]);
  const selected = hover ? byTime.get(hover.time) : undefined;
  // Leaving the plot, missing data, and an empty dataset are distinct states.
  const legend = selected ?? data[data.length - 1];

  const onCrosshairMove = useCallback((param: MouseEventParams) => {
    const series = seriesRef.current?.api();
    const container = containerRef.current;
    const point = param.point;
    if (
      !series ||
      !container ||
      !point ||
      typeof param.time !== "number" ||
      point.x < 0 ||
      point.y < 0 ||
      point.x > container.clientWidth ||
      point.y > container.clientHeight
    ) {
      setHover(null);
      return;
    }
    const bar = param.seriesData.get(series);
    if (!bar || !("close" in bar)) {
      setHover(null);
      return;
    }
    // Clamp in the same coordinate system as the positioned chart container.
    // If the card is narrower than the tooltip, CSS also shrinks its width.
    const width = Math.min(tooltipWidth, container.clientWidth);
    const x = Math.max(0, Math.min(point.x + 12, container.clientWidth - width));
    const y = Math.max(0, Math.min(point.y + 12, container.clientHeight - tooltipHeight));
    const next = { time: param.time as UTCTimestamp, x, y };
    // Native updates can emit the same crosshair event without pointer movement.
    // Preserve state identity in that case; current data still refreshes OHLC.
    setHover(previous =>
      previous?.time === next.time && previous.x === x && previous.y === y
        ? previous
        : next
    );
  }, []);

  const describe = (bar: CandlestickData<UTCTimestamp>) =>
    `O ${bar.open.toFixed(2)} · H ${bar.high.toFixed(2)} · L ${bar.low.toFixed(2)} · C ${bar.close.toFixed(2)}`;

  return (
    <section style={{ minWidth: 0 }}>
      <p>
        {symbol}: {legend ? describe(legend) : "No data"}
      </p>
      <div style={{ position: "relative" }}>
        <Chart
          containerRef={containerRef}
          containerProps={{ style: { height: 360 } }}
          options={chartOptions}
          onCrosshairMove={onCrosshairMove}
        >
          <CandlestickSeries ref={seriesRef} data={data} />
          <TimeScale>
            <TimeScaleFitContentTrigger deps={[]} />
          </TimeScale>
        </Chart>
        {hover && selected && (
          <div
            style={{
              position: "absolute",
              left: hover.x,
              top: hover.y,
              width: tooltipWidth,
              maxWidth: "100%",
              height: tooltipHeight,
              boxSizing: "border-box",
              padding: 10,
              background: "#0f172a",
              color: "white",
              borderRadius: 4,
              pointerEvents: "none", // Hover details must not steal chart pointer events.
              zIndex: 2,
            }}
          >
            <strong>{symbol}</strong>
            <div>{new Date(selected.time * 1000).toISOString().slice(0, 16)} UTC</div>
            <div style={{ fontSize: 12 }}>{describe(selected)}</div>
          </div>
        )}
      </div>
    </section>
  );
}

The plain 2-decimal formatter is appropriate only for assets with that precision. Use the same precision as the series' priceFormat for other tick sizes. For business dates, format the date fields directly; a numeric timestamp is epoch seconds and requires multiplying by 1000 before constructing a Date.

This recipe falls back to the latest candle when the hovered series has no data. If the user wants to distinguish a gap from leaving the chart, keep an explicit “gap” state and show “No bar at this time” instead. A timezone or locale formatter changes labels, never the underlying bar timestamps.

Adaptation: several series or a fixed legend

For several lines, keep refs indexed by a stable application series ID. For each series, retrieve its native API, then read param.seriesData.get(api). Display — when the map has no point; do not show another asset's value at the same logical index. Derive labels/colors from the application's ID mapping, not the order in which map entries happen to appear.

For a fixed legend, omit the floating box and position updates. Keep the selected time and derive the displayed values from the latest data, as above. For very high pointer-event rates, batch the HTML update with requestAnimationFrame; cancel the pending frame on cleanup. Avoid writing React state for every series separately within one crosshair callback.

For a tooltip in a scrollable portal attached to document.body, convert the chart-local coordinate using getBoundingClientRect() and the portal's positioning model. Do not reuse the local x/y unchanged as page coordinates. With multiple panes, param.paneIndex identifies the source pane; compute its offset or put the tooltip inside the appropriate pane container.

Acceptance checks

  • Hover first/last bars and whitespace; leave the canvas and price axis. Missing map entries never throw, the floating box disappears, and the legend falls back.

  • Update a hovered candle at the same timestamp without moving the pointer. Its OHLC changes in the legend and tooltip.

  • Hover near all four edges at a narrow width. The box remains inside the chart and does not prevent dragging, scrolling, or crosshair movement.

  • Do not suppress legend updates when only the hovered timestamp matches: a live same-bar revision keeps the time but changes the values. Guard against a missing lookup entry before reading candle fields.

  • For multi-series adaptation, test different calendars and missing points.

Requirements and compatibility

Written for: GitHub Copilot

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs Node.js

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
ukorvl
Publisher
GitHub (Official)
Distributed by
GitHub
Source
github/awesome-copilot · skills/lightweight-charts-react-components · commit 797337f
Licence
MIT License (redistribution allowed)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by ukorvl or GitHub.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download lightweight-charts-react-components.zip