Skip to content

Charts

Histogram Chart

A numeric distribution grouped into adjacent equal-width ranges.

When to use it: Use it to show shape, concentration, spread, and outliers in continuous observations.

On this page

Example

Loading example…
Histogram Chart.tsxtsx
import {
  ChartDescription,
  ChartTable,
  ChartTitle,
  ChartTooltip,
  HistogramChart,
  HistogramChartBin,
  HistogramChartPlot,
} from "@comp0/react";

const responseTimes = [180, 210, 230, 250, 270, 290, 310, 340, 380, 420, 480, 620] as const;

const formatMilliseconds = (value: number) => `${Math.round(value)} ms`;

export function Example() {
  return (
    <HistogramChart
      values={responseTimes}
      valueLabel="Response time"
      frequencyLabel="Requests"
      formatValue={formatMilliseconds}
      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">
        API response-time distribution
      </ChartTitle>
      <HistogramChartPlot
        aria-label="Histogram showing API response-time distribution"
        binCount={5}
        className="mx-auto mt-5 aspect-square w-full max-w-md overflow-visible"
      >
        {(bin) => (
          <HistogramChartBin key={bin.index} bin={bin} className="group outline-none">
            <rect
              x={bin.x}
              y={bin.y}
              width={bin.width}
              height={bin.height}
              className="fill-teal-600 stroke-white group-data-active:stroke-zinc-950 dark:fill-teal-400 dark:stroke-zinc-950 dark:group-data-active:stroke-white"
              strokeWidth="1"
              vectorEffect="non-scaling-stroke"
            />
          </HistogramChartBin>
        )}
      </HistogramChartPlot>
      <ChartDescription className="mt-5 text-sm text-zinc-600 dark:text-zinc-400">
        Most sampled requests completed below 350 milliseconds, with one slower outlier.
      </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]:sr-only" />
      <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" />
    </HistogramChart>
  );
}

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. HistogramChart

    Native figure sharing observations, labels, and value formatting. Owns a DOM element.

  2. ChartTitle

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

  3. HistogramChartPlot / HistogramChartBin

    Adjacent SVG bins positioned against value and frequency axes. Owns a DOM element.

  4. ChartDescription

    Visible prose summarizing shape and outliers. Owns a DOM element.

  5. ChartTable

    Native table that renders a complete default from the chart data: a caption from the ChartTitle text or axis labels, column headers, and one row per value. Pass children for a custom body. Owns a DOM element.

  6. ChartTooltipOptional

    Optional floating range and count shown on hover or focus. Owns a DOM element.

Step by step

  1. 1

    Add the main part

    Start HistogramChart with finite observations and visible value and frequency labels.

  2. 2

    Add the supporting parts

    Choose a meaningful binCount and wrap each rendered range in HistogramChartBin.

  3. 3

    Make the behavior clear

    Describe the distribution and keep the underlying observations or bin counts in a native ChartTable.

    Exampletsx
    <HistogramChart values={responseTimes} valueLabel="Response time" frequencyLabel="Requests">
      <ChartTitle>Response-time distribution</ChartTitle>
      <HistogramChartPlot aria-label="Histogram of response times">
        {(bin) => (
          <HistogramChartBin bin={bin}>
            <rect x={bin.x} y={bin.y} width={bin.width} height={bin.height} />
          </HistogramChartBin>
        )}
      </HistogramChartPlot>
      <ChartTable />
      <ChartTooltip />
    </HistogramChart>;

Keyboard

⇥
Enters the chart at its current bin and leaves with one more Tab.
←→
Moves between adjacent bins.
HomeEnd
Moves to the first or last bin.
Esc
Dismisses an open ChartTooltip.

Forms and accessibility

Charts are descriptive content and do not create form values.

Accessibility checklist

  • Name both the measured value axis and the frequency axis.
  • Choose bins that communicate the distribution honestly; changing bin count can materially change its appearance.
  • Wrap each custom bar in HistogramChartBin so its range and count are keyboard reachable.
  • Keep the underlying observations or exact bin counts available in a native table.
  • Adjacent bins should remain visibly separable in every color scheme.

API reference

Importtsx
import { ChartDescription, ChartTable, ChartTitle, ChartTooltip, HistogramChart, HistogramChartBin, HistogramChartPlot } from "@comp0/react";

HistogramChart

DOM element

Native figure sharing observations, labels, and value formatting.

PropTypeDescription
valuesreadonly number[]Finite observations grouped into ranges by HistogramChartPlot.
valueLabelstringVisible headings for values and counts.
frequencyLabelstringVisible headings for values and counts.
formatValue(value: number) => stringFormats range boundaries and horizontal ticks.

ChartTitle

DOM element

Native figcaption that visibly names the figure.

HistogramChartPlot / HistogramChartBin

DOM element

Adjacent SVG bins positioned against value and frequency axes.

PropTypeDescription
aria-labelstringConcise text alternative naming the distribution.
binCountnumberPositive number of equal-width bins; defaults from the observation count.
xMinnumberOptional value bounds and visible tick counts.
xMaxnumberOptional value bounds and visible tick counts.
xTickCountnumberOptional value bounds and visible tick counts.
yTickCountnumberOptional value bounds and visible tick counts.
children(bin: HistogramChartBinState) => ReactNodeCustom bin renderer receiving its range, count, and geometry.
binHistogramChartBinStateBin state passed from the plot to HistogramChartBin.

ChartDescription

DOM element

Visible prose summarizing shape and outliers.

ChartTable

DOM element

Native table that renders a complete default from the chart data: a caption from the ChartTitle text or axis labels, column headers, and one row per value. Pass children for a custom body.

ChartTooltip

OptionalDOM element

Optional floating range and count 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 bin'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.

HistogramChartPlot / HistogramChartBin

Style hookMeaning
[data-min]The inclusive lower bound of this bin.
[data-max]The upper bound of this bin.
[data-count]The number of observations in this bin.
[data-active]The bin currently reached by pointer or keyboard.

ChartTooltip

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

Keep exploring