Chart composition
Chart layout chrome, legends, stats rows, and configuration utilities
Compose chart types from Chart components with wrappers and helpers. ChartContainer adds title, loading, and empty states; ChartStatsFooter and DetailLegend add summary rows and rich legends (for example LineChartCard).
Prerequisites
Components
| Component | Description |
|---|---|
ChartContainer | Wrapper for charts with title and loading states |
MinMaxAvg | Min / max / average summary row with MDK label and value styling |
ChartContainer
Wrapper for charts with loading and empty states.
Import
import { ChartContainer } from '@tetherto/mdk-react-devkit/core'Props
| Prop | Status | Type | Default | Description |
|---|---|---|---|---|
children | Required | ReactNode | none | Chart body (for example a BarChart or LineChart) |
title | Optional | string | none | Title text |
titleExtra | Optional | ReactNode | none | Node rendered inline beside the title — use for a secondary label or unit badge |
header | Optional | ReactNode | none | Custom header node; replaces the default title row entirely when set |
headerAction | Optional | ReactNode | none | Node rendered at the trailing edge of the header row — use for action buttons such as an expand toggle |
legendData | Optional | LegendItem[] | none | Legend entries rendered in the container chrome |
highlightedValue | Optional | object | none | Highlighted metric (value, optional unit, className, style); highlight chrome renders only when this prop is set and the chart body is visible (not loading / not empty) |
rangeSelector | Optional | object | none | Range selector props (options, value, onChange, optional className, style, buttonClassName) |
loading | Optional | boolean | none | When true, shows a centered Loader overlay over the chart area |
empty | Optional | boolean | none | When true, shows empty state |
emptyMessage | Optional | string | 'No data available' | Copy shown in the empty overlay when empty is true and loading is not true |
minMaxAvg | Optional | object | none | Min / max / avg strings for the summary row |
timeRange | Optional | string | none | Time range label |
footer | Optional | ReactNode | none | Footer slot |
footerClassName | Optional | string | none | Class name on the footer wrapper |
onToggleDataset | Optional | function | none | Called with dataset index when legend toggles visibility |
className | Optional | string | none | Root class name from the host app |
Basic usage
<ChartContainer loading={isLoading} empty={data.length === 0}>
<BarChart data={data} />
</ChartContainer>ChartStatsFooter
Import
import { ChartStatsFooter } from '@tetherto/mdk-react-devkit/core'Props
| Prop | Status | Type | Default | Description |
|---|---|---|---|---|
minMaxAvg | Optional | object | none | Min, max, and average strings shown in the primary row when provided |
stats | Optional | ChartStatsFooterItem[] | none | Additional stat rows (label, value) in a columnar grid |
statsPerColumn | Optional | number | 1 | Number of stat items per column when stats is set |
secondaryLabel | Optional | object | none | Secondary block with title and value when provided |
className | Optional | string | none | Root class name from the host app |
The component renders nothing when minMaxAvg, stats, and secondaryLabel are all absent or empty.
Basic usage
<ChartStatsFooter
stats={[
{ label: 'Min', value: '120 TH/s' },
{ label: 'Max', value: '180 TH/s' },
{ label: 'Avg', value: '150 TH/s' },
]}
/>DetailLegend
Import
import { DetailLegend } from '@tetherto/mdk-react-devkit/core'Props
| Prop | Status | Type | Default | Description |
|---|---|---|---|---|
items | Required | DetailLegendItem[] | none | Legend rows (label, color, optional icon, currentValue, percentChange, hidden) |
onToggle | Optional | function | none | Called with label and index when a row is toggled |
className | Optional | string | none | Root class name from the host app |
Basic usage
<DetailLegend
items={[
{ label: 'Online', color: '#72F59E', currentValue: { value: 85, unit: '%' } },
{ label: 'Offline', color: '#FF6B6B', currentValue: { value: 15, unit: '%' } },
]}
/>MinMaxAvg
Compact summary row rendering min, max, and average values with MDK label and value styling. Items with empty values are omitted. Use standalone or via the minMaxAvg prop on ChartContainer.
Renders a compact, horizontally spaced row of min, max, and average values with MDK label and value styling. Only items with a non-empty value are rendered; the component returns null when all three are absent.
Pair it with ChartContainer via the minMaxAvg prop to attach the summary row below a chart automatically, or use MinMaxAvg standalone for custom layouts.
Import
import { MinMaxAvg } from '@tetherto/mdk-react-devkit/core'
import type { MinMaxAvgProps } from '@tetherto/mdk-react-devkit/core'Props
| Prop | Status | Type | Default | Description |
|---|---|---|---|---|
min | Optional | string | none | Minimum value string (for example '10 TH/s'); omitted items are not rendered |
max | Optional | string | none | Maximum value string |
avg | Optional | string | none | Average value string |
className | Optional | string | none | Root class name from the host app |
Basic usage
import { MinMaxAvg } from '@tetherto/mdk-react-devkit/core'
<MinMaxAvg min="10 TH/s" max="100 TH/s" avg="55 TH/s" />Via ChartContainer
Pass pre-formatted strings to the minMaxAvg prop on ChartContainer to mount MinMaxAvg in the chart footer automatically:
import { ChartContainer, LineChart, computeStats } from '@tetherto/mdk-react-devkit/core'
const { min, max, avg } = computeStats(values)
const fmt = (n: number) => `${n.toFixed(2)} TH/s`
<ChartContainer
title="Hashrate"
minMaxAvg={{ min: fmt(min), max: fmt(max), avg: fmt(avg) }}
>
<LineChart data={chartData} />
</ChartContainer>Use the computeStats utility (see Chart utilities) to compute the values from a numeric array before formatting them.
Styling
.mdk-min-max-avg: Root element (role="group").mdk-min-max-avg__item: Individual min / max / avg item.mdk-min-max-avg__label: Label text ("Min", "Max", "Avg").mdk-min-max-avg__value: Value text
Chart utilities
Pure functions for building Chart.js data and options. Import from the package root alongside components.
import {
defaultChartOptions,
defaultChartColors,
buildBarChartData,
buildBarChartOptions,
buildChartTooltip,
computeStats,
} from '@tetherto/mdk-react-devkit/core'| Export | Role |
|---|---|
defaultChartOptions | Shared Chart.js defaults used by MDK chart components |
defaultChartColors | Default dataset color palette |
buildBarChartData | Map MDK bar input into Chart.js data |
buildBarChartOptions | Build bar chart options (stacking, axes, formatters) |
buildChartTooltip | HTML tooltip config for Chart.js |
computeStats | Min, max, and average for a numeric array |
Types BarChartInput, BarChartSeries, BarChartLine, and BarChartConstant are exported from the same package for hook-shaped bar data.
Hook-shaped bar data
App and reporting hooks often return declarative bar input instead of Chart.js data. buildBarChartData converts that shape
into { labels, datasets } for BarChart. The pipeline:
- Input (
BarChartInput): optionallabels, requiredseries, optionallinesandconstantsfor mixed bar/line overlays. - Build (
buildBarChartData): returns Chart.jsdatawith MDK gradient styling and layout defaults (barWidth,categoryPercentage,barPercentageare optional on the input). - Data labels (optional): per-series overrides on the input (
formatter,anchor,align,offset,font,padding,display,clamp,clip) map to each built dataset’s Chart.jsdatalabelsby series index. - Render (
<BarChart data={...} />): pass the built object to the component; pair withbuildBarChartOptionswhen you need stacking, axes, or formatters.
BarChartInput shape
| Field | Type | Description |
|---|---|---|
labels | string[] | Optional category labels; omitted labels are derived from series values keys or indices |
series | BarChartSeries[] | Bar datasets (label, values, optional color, stack, gradient, bar layout props) |
lines | BarChartLine[] | Optional line overlays on the same chart |
constants | BarChartConstant[] | Optional horizontal reference lines |
Each BarChartSeries uses values as either number[] (positional) or Record<string, number> (keyed by category label).
Example
Hook output to BarChart example:
import {
BarChart,
buildBarChartData,
ChartContainer,
} from '@tetherto/mdk-react-devkit/core'
// Typical shape returned by app/reporting data hooks
const hookOutput = {
labels: ['Q1', 'Q2', 'Q3'],
series: [
{
label: 'Revenue',
values: [4.2, 3.8, 5.1],
color: '#72F59E',
dataLabels: {
formatter: (v: number) => `${v.toFixed(1)}M`,
anchor: 'end',
align: 'top',
},
},
{
label: 'OpEx',
values: [1.8, 2.0, 1.6],
color: '#FFD700',
},
],
}
const cleanSeries = hookOutput.series.map(({ dataLabels: _dl, ...s }) => s)
const base = buildBarChartData({ labels: hookOutput.labels, series: cleanSeries })
const chartData = {
labels: base.labels,
datasets: base.datasets.map((dataset, i) => {
const overrides = hookOutput.series[i]?.dataLabels
return overrides ? { ...dataset, datalabels: overrides } : dataset
}),
}
const isEmpty =
!hookOutput.series.length ||
hookOutput.series.every((s) => {
const vals = Array.isArray(s.values) ? s.values : Object.values(s.values)
return !vals.length || vals.every((v) => v === 0)
})
<ChartContainer title="Quarterly" empty={isEmpty}>
<BarChart data={chartData} />
</ChartContainer>Empty and all-zero series
Treat bar data as empty when any of the following is true:
seriesis missing or has length0- Every series has empty
values(array or record) - Every numeric value across all series is
0
Prefer ChartContainer empty or a placeholder instead of rendering a flat chart. After building Chart.js data, you can also
use useChartDataCheck from @tetherto/mdk-react-devkit/foundation
with { data: chartData }.