Trade Chart
A theme-aware candlestick chart built on TradingView Lightweight Charts
import { TradeChart } from "@/components/sol/trade-chart";
export function TradeChartDemo() {
return (
<TradeChart
data={[
{ time: "2026-01-01", open: 148.32, high: 150.10, low: 145.60, close: 145.81 },
{ time: "2026-01-02", open: 145.81, high: 148.50, low: 144.90, close: 147.22 },
{ time: "2026-01-03", open: 147.22, high: 152.00, low: 146.80, close: 151.45 },
]}
visibleBars={30}
/>
);
}Installation
pnpm dlx shadcn@latest add @solanaui/trade-chart
npx shadcn@latest add @solanaui/trade-chart
yarn dlx shadcn@latest add @solanaui/trade-chart
Usage
<TradeChart
data={[
{ time: "2026-01-01", open: 148.32, high: 150.10, low: 145.60, close: 145.81 },
{ time: "2026-01-02", open: 145.81, high: 148.50, low: 144.90, close: 147.22 },
{ time: "2026-01-03", open: 147.22, high: 152.00, low: 146.80, close: 151.45 },
]}
visibleBars={30}
/>Source Code
"use client";import type { CandlestickData, CandlestickSeriesPartialOptions, DeepPartial, TimeChartOptions,} from "lightweight-charts";import { CandlestickSeries, ColorType, createChart } from "lightweight-charts";import React from "react";interface TradeChartProps { data: CandlestickData[]; visibleBars?: number; className?: string; chartOptions?: DeepPartial<TimeChartOptions>; seriesOptions?: DeepPartial<CandlestickSeriesPartialOptions>;}const LIGHT_COLORS = { background: "rgb(255, 255, 255)", foreground: "rgb(37, 37, 37)", border: "rgb(235, 235, 235)", mutedForeground: "rgb(142, 142, 142)",};const DARK_COLORS = { background: "rgb(37, 37, 37)", foreground: "rgb(251, 251, 251)", border: "rgba(255, 255, 255, 0.1)", mutedForeground: "rgb(180, 180, 180)",};const TradeChart = ({ data, visibleBars, className = "h-[320px] w-full", chartOptions, seriesOptions,}: TradeChartProps) => { const containerRef = React.useRef<HTMLDivElement>(null); const chartRef = React.useRef<ReturnType<typeof createChart> | null>(null); const [isDark, setIsDark] = React.useState(() => { if (typeof window === "undefined") return false; return document.documentElement.classList.contains("dark"); }); // Watch for theme changes on <html> class React.useEffect(() => { const observer = new MutationObserver(() => { setIsDark(document.documentElement.classList.contains("dark")); }); observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"], }); return () => observer.disconnect(); }, []); // Stable serialized keys so inline object literals don't cause re-renders const chartOptionsKey = JSON.stringify(chartOptions); const seriesOptionsKey = JSON.stringify(seriesOptions); React.useEffect(() => { if (!containerRef.current) return; const parsedChartOptions = chartOptionsKey ? (JSON.parse(chartOptionsKey) as DeepPartial<TimeChartOptions>) : undefined; const parsedSeriesOptions = seriesOptionsKey ? (JSON.parse( seriesOptionsKey, ) as DeepPartial<CandlestickSeriesPartialOptions>) : undefined; const colors = isDark ? DARK_COLORS : LIGHT_COLORS; const defaultChartOptions: DeepPartial<TimeChartOptions> = { layout: { textColor: colors.foreground, background: { type: ColorType.Solid as const, color: colors.background, }, fontFamily: "var(--font-geist-sans)", }, grid: { vertLines: { color: colors.border, style: 1 }, horzLines: { color: colors.border, style: 1 }, }, crosshair: { vertLine: { color: colors.mutedForeground, width: 1, style: 3, }, horzLine: { color: colors.mutedForeground, width: 1, style: 3, }, }, rightPriceScale: { borderColor: colors.border }, timeScale: { borderColor: colors.border, timeVisible: true }, autoSize: true, ...parsedChartOptions, }; chartRef.current = createChart(containerRef.current, defaultChartOptions); const candlestick = chartRef.current.addSeries(CandlestickSeries, { borderVisible: false, ...parsedSeriesOptions, }); candlestick.setData(data); if (visibleBars && data.length > visibleBars) { chartRef.current.timeScale().setVisibleLogicalRange({ from: data.length - visibleBars - 0.5, to: data.length - 0.5, }); } else { chartRef.current.timeScale().fitContent(); } return () => { chartRef.current?.remove(); }; }, [data, visibleBars, isDark, chartOptionsKey, seriesOptionsKey]); return <div className={className} ref={containerRef} />;};export type { TradeChartProps };export { TradeChart };