Skip to content
design
Components

Chart panel

Frame a chart, report figure or map with a title, controls, legend and source information.

On this page

Processing time

Illustrative data · Monday through Sunday

  • Service
  • Comparison
Milliseconds per request · illustrative observations
Frame a chart, report figure or map with a title, controls, legend and source information.
Code
import { LineChart } from "@bosunkit/components/line-chart";
import { ChartLegend } from "@bosunkit/components/chart-legend";
import { ChartPanel } from "@bosunkit/components/chart-panel";
import type { ChartConfig } from "@bosunkit/components/chart-container";
import { ReferenceLine } from "recharts";
import type { ReactElement } from "react";

export const description: string =
  "Illustrative processing times over a week, with a missing Wednesday and a reference at eight milliseconds.";

interface Sample {
  readonly day: string;
  readonly service: number | null;
  readonly comparison: number | null;
}
const data: readonly Sample[] = [
  { day: "Mon", service: 6, comparison: 8 },
  { day: "Tue", service: 5, comparison: 7 },
  { day: "Wed", service: null, comparison: 7 },
  { day: "Thu", service: 4, comparison: 6 },
  { day: "Fri", service: 3, comparison: 5 },
  { day: "Sat", service: 4, comparison: 5 },
  { day: "Sun", service: 2, comparison: 4 },
];
// These are supplied display strings for the fixed, illustrative fixture. A consumer passes its quantity formatter.
const values: Readonly<Record<number, string>> = {
  0: "0 ms",
  1: "1 ms",
  2: "2 ms",
  3: "3 ms",
  4: "4 ms",
  5: "5 ms",
  6: "6 ms",
  7: "7 ms",
  8: "8 ms",
  9: "9 ms",
  10: "10 ms",
};
const writeValue: (value: number) => string = (value: number): string => values[value] ?? "";
const writeDay: (value: string | number) => string = (value: string | number): string =>
  typeof value === "string" ? value : "";
const config: ChartConfig<Sample> = {
  service: { label: "Service", formatValue: writeValue },
  comparison: { label: "Comparison", formatValue: writeValue },
};

export default function WeeklyLatency(): ReactElement {
  return (
    <ChartPanel
      title="Processing time"
      description="Illustrative data · Monday through Sunday"
      legend={<ChartLegend config={config} label="Processing time series" />}
      footer="Milliseconds per request · illustrative observations"
    >
      <LineChart
        data={data}
        categoryKey="day"
        config={config}
        series={["service", "comparison"]}
        formatCategory={writeDay}
        formatAxisValue={writeValue}
        valueDomain={[0, 10]}
        label="Illustrative processing times, Monday through Sunday"
        categoryLabel="Day"
        dataTableLabel="View processing times"
        missingValueText="Not measured"
      >
        <ReferenceLine y={8} label={{ value: "Reference · 8 ms", position: "top" }} />
      </LineChart>
    </ChartPanel>
  );
}

The chart panel names a region by its title. It places actions in the header, controls above the drawing, a legend below it and source information in the footer. The drawing and its data belong to its children.

01One series definitionNames, palette slots and patterns come from the same registry used by the drawing.
02Caller-formatted valuesThe caller supplies display text and quantity formatters; missing values have an explicit description.
03Accessible inspectionNames and patterns supplement color, and analytical plots expose their observations in a source table.

Use

Loading, empty and error states occupy the plot's space. Empty and error states use caller-supplied messages and remove the plot. The chart container supplies its own definite height; the panel's minimum plot height does not size a percentage-height chart. A standalone legend receives its registry explicitly. A map, analytical chart or instrument trend can use the same frame.

Examples

Composition

Processing time

Illustrative data · Monday through Sunday

  • Service
  • Comparison
Milliseconds per request · illustrative observations
Illustrative processing times over a week, with a missing Wednesday and a reference at eight milliseconds.
Code
import { LineChart } from "@bosunkit/components/line-chart";
import { ChartLegend } from "@bosunkit/components/chart-legend";
import { ChartPanel } from "@bosunkit/components/chart-panel";
import type { ChartConfig } from "@bosunkit/components/chart-container";
import { ReferenceLine } from "recharts";
import type { ReactElement } from "react";

export const description: string =
  "Illustrative processing times over a week, with a missing Wednesday and a reference at eight milliseconds.";

interface Sample {
  readonly day: string;
  readonly service: number | null;
  readonly comparison: number | null;
}
const data: readonly Sample[] = [
  { day: "Mon", service: 6, comparison: 8 },
  { day: "Tue", service: 5, comparison: 7 },
  { day: "Wed", service: null, comparison: 7 },
  { day: "Thu", service: 4, comparison: 6 },
  { day: "Fri", service: 3, comparison: 5 },
  { day: "Sat", service: 4, comparison: 5 },
  { day: "Sun", service: 2, comparison: 4 },
];
// These are supplied display strings for the fixed, illustrative fixture. A consumer passes its quantity formatter.
const values: Readonly<Record<number, string>> = {
  0: "0 ms",
  1: "1 ms",
  2: "2 ms",
  3: "3 ms",
  4: "4 ms",
  5: "5 ms",
  6: "6 ms",
  7: "7 ms",
  8: "8 ms",
  9: "9 ms",
  10: "10 ms",
};
const writeValue: (value: number) => string = (value: number): string => values[value] ?? "";
const writeDay: (value: string | number) => string = (value: string | number): string =>
  typeof value === "string" ? value : "";
const config: ChartConfig<Sample> = {
  service: { label: "Service", formatValue: writeValue },
  comparison: { label: "Comparison", formatValue: writeValue },
};

export default function WeeklyLatency(): ReactElement {
  return (
    <ChartPanel
      title="Processing time"
      description="Illustrative data · Monday through Sunday"
      legend={<ChartLegend config={config} label="Processing time series" />}
      footer="Milliseconds per request · illustrative observations"
    >
      <LineChart
        data={data}
        categoryKey="day"
        config={config}
        series={["service", "comparison"]}
        formatCategory={writeDay}
        formatAxisValue={writeValue}
        valueDomain={[0, 10]}
        label="Illustrative processing times, Monday through Sunday"
        categoryLabel="Day"
        dataTableLabel="View processing times"
        missingValueText="Not measured"
      >
        <ReferenceLine y={8} label={{ value: "Reference · 8 ms", position: "top" }} />
      </LineChart>
    </ChartPanel>
  );
}

Unavailable

Daily work

Monday through Friday

The report could not be loaded. Your saved report is unchanged. Try opening it again.
An unavailable dataset has a specific message and no stale plot.
Code
import { ChartPanel } from "@bosunkit/components/chart-panel";
import type { ReactElement } from "react";
export const description: string = "An unavailable dataset has a specific message and no stale plot.";
export default function Unavailable(): ReactElement {
  return (
    <ChartPanel
      title="Daily work"
      description="Monday through Friday"
      state="error"
      stateMessage="The report could not be loaded. Your saved report is unchanged. Try opening it again."
    />
  );
}

State and evidence around the drawing

Use the title to state the subject, the description to define the comparison, and the footer for source, period and aggregation. Keep a chart's unit and time reference visible when inspection is closed. A useful panel can contain a diagram or map as well as an analytical chart.

Distinguish an initial load from a refresh of known data. A successful query with no observations is different from a failed request. Supply the appropriate state and recovery action without changing the meaning of the window's label. Keep the source table and important conclusions accessible in a report or print view.

Props

appearance="analytical" uses the analytical surface, header divider and plot insets. It gives comparison charts the reference dashboard's framing while the drawing, palette, labels and source values remain caller-supplied.

PropTypeDefaultDescription
appearance"default" | "analytical" | undefined"default"Default kit frame, or an analytical dashboard frame with a separated header and blue-reference roles.
titlerequiredReactNode–The panel's title, as display text; it names the panel, which is then a region.
descriptionReactNode | undefined–A line under the title saying what the chart shows and over what window.
headingLevelNestedHeadingLevel | undefined3The level of the title's heading element, so the panel sits in the page's outline; 3 by default.
actionsReactNode | undefined–Controls at the header's end: an icon button that opens the chart's page, a menu, a link.
controlsReactNode | undefined–The toolbar between the header and the plot: a time range select, series filters, a granularity switch.
legendReactNode | undefined–The legend under the plot: the series' names and colors, or the map key.
footerReactNode | undefined–A row under the plot and the legend, set off by a rule: the source, or a time with its reference.
stateChartPanelState | undefined"ready"What the plot shows. ready (the default) draws children; loading draws a placeholder of the plot's own height; empty and error draw stateMessage in its place, the error in a message band.
stateMessageReactNode | undefined–The words shown instead of the plot when the state is empty or error; translated by the caller.
plotMinHeightnumber | string | undefined"10em"The plot's smallest height: pixels, or any CSS length. 10em by default, so a responsive chart has room.
childrenReactNode | undefined–The chart drawing, with its axes and marks.
classNamestring | undefined–Classes added to the root's own.
testIdstring | undefined–Becomes data-testid on the root; the parts are ${testId}--title, --controls, --plot, --legend and --footer.
refRef<HTMLElement> | undefined–The root element.
Do

Processing time

Illustrative data · Monday through Sunday

  • Service
  • Comparison
Milliseconds per request · illustrative observations
Name the observations and keep the comparison basis visible.
Don't

Keep a gap and describe the missing measurement in the source table.

A missing observation must not appear to be zero.
  • Data visualization: scales, missing measurements and comparable evidence.
  • Chart container: responsive drawing and registry scope.
  • Sparkline: compact trends with operational integrity and forecast information.