Skip to content

Charts

Candlestick Chart

An open-high-low-close financial series with visible axes and every exact value in a native table.

When to use it: Use it for ordered market prices where both the range and movement within each period matter.

On this page

Example

Loading example…
Candlestick Chart.tsxtsx
import {
  CandlestickChart,
  CandlestickChartCandle,
  CandlestickChartPlot,
  ChartDescription,
  ChartTable,
  ChartTitle,
  ChartTooltip,
} from "@comp0/react";

const prices = [
  { x: 1, open: 184, high: 192, low: 181, close: 190 },
  { x: 2, open: 190, high: 194, low: 186, close: 188 },
  { x: 3, open: 188, high: 197, low: 187, close: 195 },
  { x: 4, open: 195, high: 198, low: 189, close: 191 },
] as const;

const formatDay = (value: number | Date) => `Day ${value}`;
const formatPrice = (value: number) => `$${value}`;

export function Example() {
  return (
    <CandlestickChart
      values={prices}
      xLabel="Trading day"
      yLabel="Share price"
      formatX={formatDay}
      formatY={formatPrice}
      className="w-full max-w-2xl rounded-lg has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-4 has-[:focus-visible]:outline-teal-600 dark:has-[:focus-visible]:outline-teal-400"
    >
      <ChartTitle className="text-base font-semibold text-zinc-950 dark:text-zinc-50">
        Four-day share price
      </ChartTitle>
      <CandlestickChartPlot
        aria-label="Candlestick chart showing four days of share prices"
        className="mx-auto mt-5 aspect-square w-full max-w-md overflow-visible"
      >
        {(candle) => (
          <CandlestickChartCandle candle={candle} className="group outline-none">
            <line
              x1={candle.x}
              x2={candle.x}
              y1={candle.highY}
              y2={candle.lowY}
              data-direction={candle.direction}
              className="stroke-rose-600 data-[direction=up]:stroke-teal-600 group-data-active:stroke-zinc-950 dark:stroke-rose-400 dark:data-[direction=up]:stroke-teal-400 dark:group-data-active:stroke-white"
              strokeWidth="2"
              vectorEffect="non-scaling-stroke"
            />
            <rect
              x={candle.x - candle.width / 2}
              y={candle.bodyY}
              width={candle.width}
              height={candle.bodyHeight}
              data-direction={candle.direction}
              className="fill-rose-600 stroke-rose-600 data-[direction=up]:fill-white data-[direction=up]:stroke-teal-600 group-data-active:stroke-zinc-950 dark:fill-rose-400 dark:stroke-rose-400 dark:data-[direction=up]:fill-zinc-950 dark:data-[direction=up]:stroke-teal-400 dark:group-data-active:stroke-white"
              strokeWidth="2"
              vectorEffect="non-scaling-stroke"
            />
            <rect
              aria-hidden="true"
              x={candle.x - candle.width / 2 - 1.5}
              y={candle.highY - 1.5}
              width={candle.width + 3}
              height={candle.lowY - candle.highY + 3}
              rx="1.5"
              className="pointer-events-none fill-none stroke-transparent group-data-active:stroke-zinc-950 dark:group-data-active:stroke-white"
              strokeWidth="2"
              vectorEffect="non-scaling-stroke"
            />
          </CandlestickChartCandle>
        )}
      </CandlestickChartPlot>
      <ChartDescription className="mt-5 text-sm text-zinc-600 dark:text-zinc-400">
        The price reached its highest close on day three before falling on day four.
      </ChartDescription>
      <ChartTable className="mt-4 w-full border-collapse text-left text-sm [&_td]:border-t [&_td]:border-zinc-200 [&_td]:py-2 [&_th]:border-zinc-200 [&_th]:py-2 dark:[&_td]:border-zinc-800 dark:[&_th]:border-zinc-800">
        <caption className="sr-only">Daily open, high, low, and close share prices</caption>
        <thead>
          <tr>
            <th scope="col">Trading day</th>
            <th scope="col">Open</th>
            <th scope="col">High</th>
            <th scope="col">Low</th>
            <th scope="col">Close</th>
          </tr>
        </thead>
        <tbody>
          {prices.map((price) => (
            <tr key={price.x}>
              <th scope="row">{formatDay(price.x)}</th>
              <td>{formatPrice(price.open)}</td>
              <td>{formatPrice(price.high)}</td>
              <td>{formatPrice(price.low)}</td>
              <td>{formatPrice(price.close)}</td>
            </tr>
          ))}
        </tbody>
      </ChartTable>
      <ChartTooltip className="pointer-events-none z-50 rounded-md bg-zinc-950 px-2 py-1 text-sm text-white shadow-lg dark:bg-zinc-50 dark:text-zinc-950" />
    </CandlestickChart>
  );
}

Anatomy

Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.

A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.

  1. CandlestickChart

    Native figure sharing ordered OHLC values, labels, and formatting with every part. Owns a DOM element.

  2. ChartTitle

    Native figcaption that visibly names the figure. Owns a DOM element.

  3. CandlestickChartPlot / CandlestickChartCandle

    SVG wicks and bodies positioned against visible time and value axes. Owns a DOM element.

  4. ChartDescription

    Visible prose summarizing the important movement. Owns a DOM element.

  5. ChartTable

    Native table composed with an explicit caption, headers, and rows from the chart values. Owns a DOM element.

  6. ChartTooltipOptional

    Optional floating OHLC label shown on hover or focus. Owns a DOM element.

Step by step

  1. 1

    Add the main part

    Start CandlestickChart with strictly increasing x values and valid open, high, low, and close prices.

  2. 2

    Add the supporting parts

    Add ChartTitle and CandlestickChartPlot; wrap each rendered candle in CandlestickChartCandle so one candle is tabbable and horizontal arrow keys reveal the rest.

  3. 3

    Make the behavior clear

    Add ChartDescription and ChartTable for persistent context and exact OHLC values; optionally add ChartTooltip for pointer and keyboard details.

    Exampletsx
    <CandlestickChart values={prices} xLabel="Trading day" yLabel="Share price">
      <ChartTitle>Four-day share price</ChartTitle>
      <CandlestickChartPlot aria-label="Candlestick chart showing four days of share prices">
        {(candle) => (
          <CandlestickChartCandle candle={candle}>
            <rect
              x={candle.x - candle.width / 2}
              y={candle.bodyY}
              width={candle.width}
              height={candle.bodyHeight}
            />
          </CandlestickChartCandle>
        )}
      </CandlestickChartPlot>
      <ChartDescription>The highest close occurred on day three.</ChartDescription>
      <ChartTable>
        <caption>Daily OHLC values</caption>
        <thead>
          <tr>
            <th scope="col">Day</th>
            <th scope="col">Open</th>
            <th scope="col">High</th>
            <th scope="col">Low</th>
            <th scope="col">Close</th>
          </tr>
        </thead>
        <tbody>
          {prices.map((price) => (
            <tr key={price.x}>
              <th scope="row">Day {price.x}</th>
              <td>${price.open}</td>
              <td>${price.high}</td>
              <td>${price.low}</td>
              <td>${price.close}</td>
            </tr>
          ))}
        </tbody>
      </ChartTable>
      <ChartTooltip />
    </CandlestickChart>;

Keyboard

Enters the chart at its current candle and leaves with one more Tab.
Moves to the next candle without wrapping.
Moves to the previous candle without wrapping.
Home
Moves to the first candle.
End
Moves to the last candle.
Esc
Dismisses an open ChartTooltip.

Forms and accessibility

Charts are descriptive content and do not create form values.

Accessibility checklist

  • Keep both axis labels visible and format ticks with the same units used in ChartTable.
  • Give CandlestickChartPlot a concise aria-label that identifies the instrument and period.
  • Wrap custom marks in CandlestickChartCandle to expose one roving tab stop; each candle receives its formatted time and OHLC values as a name.
  • ChartTooltip is an optional visual enhancement for hover and focus; never make it the only source of a value.
  • Include ChartTable so every open, high, low, and close value remains directly readable.
  • Distinguish rising and falling candles with shape or fill treatment as well as color.

API reference

Importtsx
import { CandlestickChart, CandlestickChartCandle, CandlestickChartPlot, ChartDescription, ChartTable, ChartTitle, ChartTooltip } from "@comp0/react";

CandlestickChart

DOM element

Native figure sharing ordered OHLC values, labels, and formatting with every part.

PropTypeDescription
valuesreadonly CandlestickChartValue[]Strictly increasing x values with finite open, high, low, and close values.
xLabelstringVisible headings for the time and value axes.
yLabelstringVisible headings for the time and value axes.
openLabelstringTable headings for each financial value.
highLabelstringTable headings for each financial value.
lowLabelstringTable headings for each financial value.
closeLabelstringTable headings for each financial value.
formatX(value) => stringFormatters shared by axis ticks and table cells.
formatY(value) => stringFormatters shared by axis ticks and table cells.

ChartTitle

DOM element

Native figcaption that visibly names the figure.

CandlestickChartPlot / CandlestickChartCandle

DOM element

SVG wicks and bodies positioned against visible time and value axes.

PropTypeDescription
aria-labelstringConcise text alternative naming the instrument and period.
yMinnumberOptional finite vertical scale bounds.
yMaxnumberOptional finite vertical scale bounds.
yTickCountnumberVisible vertical-axis tick count; defaults to five.
children(candle: CandlestickChartCandleState) => ReactNodeCustom candle renderer receiving its OHLC value, direction, and SVG geometry.
candleCandlestickChartCandleStateCandle state passed from the plot to CandlestickChartCandle.
CandlestickChartCandle childrenReactNodeSVG shapes grouped into one named, keyboard-reachable candle.

ChartDescription

DOM element

Visible prose summarizing the important movement.

ChartTable

DOM element

Native table composed with an explicit caption, headers, and rows from the chart values.

PropTypeDescription
childrenReactNodeNative caption, thead, tbody, and optional tfoot markup.

ChartTooltip

OptionalDOM element

Optional floating OHLC label shown on hover or focus.

PropTypeDescription
placementPopoverPlacementSide of the active mark; defaults to "top".
offsetnumberDistance from the active mark; defaults to eight pixels.
childrenReactNode | (details: ChartValueDetails) => ReactNodeCustom content receiving the active candle's formatted details.

Style hooks

Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.

CandlestickChartPlot / CandlestickChartCandle

Style hookMeaning
[data-direction]The candle closed "up", "down", or "unchanged" from its opening value.
[data-active]The candle currently reached by pointer or keyboard.

ChartTooltip

Style hookMeaning
[data-open]A value tooltip is visible.

Keep exploring