Charts and Widgets
Overview
The chart module and the three card modules cover dashboard surfaces: a chart of a series, a single figure with a delta, a ranked list, and the period selector the others read their date range from. Each one is a builder that produces a component description; each one either carries its data inline (staticDataset, staticItems, staticValue) or names a fetchUrl the frontend calls.
All of them are exported from the package root; the charts also have their own subpath.
import {
ChartArea,
ChartCard,
KpiCard,
PeriodSelector,
TopListCard,
} from "@antelopejs-private/cms/interfaces/cms-base";
// charts only
import { ChartLine, ChartType } from "@antelopejs-private/cms/interfaces/cms-base/chart";
A Dashboard in One Page
The widgets compose through the layout builders from Layout and Containers. One PeriodSelector declares a scope id; every widget that names the same periodScope follows its range.
import {
PageController,
pagesCategory,
RegisterPage,
} from "@antelopejs-private/cms/interfaces/cms/page";
import {
ChartArea,
ChartCard,
KpiCard,
PeriodSelector,
TopListCard,
} from "@antelopejs-private/cms/interfaces/cms-base";
import { Grid, GridRow } from "@antelopejs-private/cms/interfaces/cms-base/grid";
import { DefaultLayout } from "@antelopejs-private/cms/interfaces/cms-base/layouts";
const SCOPE_ID = "ai-overview";
@RegisterPage()
export class OverviewPage extends PageController(
"overview",
{ displayName: "Overview", icon: "i-ph-chart-line", category: pagesCategory },
DefaultLayout({ fullWidth: true }),
) {
static periodSelector = PeriodSelector({
id: SCOPE_ID,
align: "right",
defaultPreset: "last-7-days",
defaultComparison: "previous-period",
presets: ["today", "last-7-days", "last-30-days"],
});
static kpis = Grid({ gap: "1rem" }).child(
"kpiRow",
GridRow().child(
"actions",
KpiCard({
title: "Actions",
icon: "i-ph-lightning",
fetchUrl: "/ai/metrics/kpi/actions",
periodScope: SCOPE_ID,
valueFormat: "compact",
compareLabel: "vs previous period",
}),
),
);
static activityRow = Grid({ gap: "1rem" }).child(
"row",
GridRow()
.child(
"activityChart",
ChartCard({
title: "AI activity",
description: "Actions over the selected period",
icon: "i-ph-chart-line",
fetchUrl: "/ai/metrics/series",
periodScope: SCOPE_ID,
valueFormat: "compact",
chart: ChartArea({ xaxisType: "datetime" }),
}),
{ colSpan: 2 },
)
.child(
"topSkills",
TopListCard({
title: "Top skills",
fetchUrl: "/ai/metrics/top-skills?limit=5",
periodScope: SCOPE_ID,
}),
),
);
}
Chart Builders
There is one builder per chart type. Each takes its own props with the type discriminant optional — the builder fills it in — and returns a ComponentBuilder for that props type.
| Builder | ChartType | Props interface |
|---|---|---|
ChartLine | LINE | LineChartProps |
ChartArea | AREA | AreaChartProps |
ChartRangeArea | RANGE_AREA | RangeAreaChartProps |
ChartBar | BAR | BarChartProps |
ChartColumn | COLUMN | ColumnChartProps |
ChartScatter | SCATTER | ScatterChartProps |
ChartMixed | MIXED | MixedChartProps |
ChartRadar | RADAR | RadarChartProps |
ChartCandlestick | CANDLESTICK | CandlestickChartProps |
ChartDonut | DONUT | DonutChartProps |
ChartPie | PIE | PieChartProps |
ChartRadialBar | RADIAL_BAR | RadialBarChartProps |
ChartHeatmap | HEATMAP | HeatmapChartProps |
ChartType is the enum behind the discriminant: LINE, AREA, RANGE_AREA, BAR, COLUMN, SCATTER, DONUT, PIE, MIXED, RADAR, RADIAL_BAR, HEATMAP, CANDLESTICK. AnyChartProps is the union of all thirteen props interfaces.
Every builder gives the component a display name from title, falling back to the chart's own name ("Line Chart", "Donut Chart", …), and a matching icon.
Common Options
Every chart props interface extends BaseComponentProps and adds:
| Option | Type | Description |
|---|---|---|
title | string | Chart title, also the component display name. |
description | string | Chart description. |
color | ChartColor | One colour or a colour list. |
height | string | CSS height. |
width | number | Width. |
showTooltip | boolean | Show the value tooltip. |
showLegend | boolean | Show the series legend. |
fetchUrl | string | URL the chart loads its data from. |
fetchUrlMethod | HttpMethod | Method for fetchUrl. |
periodScope | string | Id of the PeriodSelector whose range this chart follows. |
realtimeTopic | string | string[] | Realtime topics to subscribe the page to. |
rawOptions | KeyValuePair[] | Escape hatch: extra key/value options passed through to the chart renderer. |
rawCss | KeyValuePair[] | Escape hatch: extra key/value CSS declarations. |
KeyValuePair is { key: string; value: string }.
When realtimeTopic is set, the builder registers each topic against the page it is declared on, using RegisterPageTopic from the cms interface.
Cartesian Charts
LineChartProps, AreaChartProps, RangeAreaChartProps, BarChartProps, ColumnChartProps, ScatterChartProps, MixedChartProps, RadarChartProps and CandlestickChartProps share a second layer of options on top of the common ones:
| Option | Type | Description |
|---|---|---|
staticDataset | ChartSeries[] | Inline data, as an alternative to fetchUrl. |
showGrid | boolean | Draw the background grid. |
yRange | { min: number; max: number } | Fixed Y bounds. |
comparisonStyle | ComparisonStyle | How the comparison series is drawn: "dashed", "solid" or "dimmed". |
smooth | boolean | Smooth the line between points. |
curve | ChartCurve | Line interpolation, honoured by the line, area, rangeArea and mixed types. Takes precedence over smooth when both are set. |
annotations | ChartAnnotation[] | Horizontal reference lines on the Y axis. |
syncGroup | string | Charts sharing a group name share their crosshair and tooltip position. |
xaxisType | "category" | "datetime" | "numeric" | Interpretation of the X values. |
And each adds its own:
| Props | Extra options |
|---|---|
LineChartProps | strokeWidth?: number |
AreaChartProps | fillOpacity?: number, stacked?: boolean |
RangeAreaChartProps | fillOpacity?: number |
BarChartProps | stacked?: boolean, barWidth?: number, roundedCorners?: boolean, orientation?: AxeOrientation |
ColumnChartProps | stacked?: boolean, columnWidth?: number, roundedCorners?: boolean |
ScatterChartProps | pointSize?: number, showLabels?: boolean |
MixedChartProps | seriesDefs?: MixedChartSeriesDef[] |
RadarChartProps | fillOpacity?: number |
CandlestickChartProps | — |
MixedChartSeriesDef declares how one series of a mixed chart is drawn: { name: string; type: ChartType.LINE | ChartType.AREA | ChartType.COLUMN | ChartType.RANGE_AREA; color?: ChartColorValue }.
ChartCurve is "smooth" | "straight" | "stepline". Prefer it to smooth, which only chooses between the first two.
ChartAnnotation draws a horizontal reference on the Y axis — a spend cap, a max bound, a volume capacity:
| Field | Type | Description |
|---|---|---|
y | number | Value the line sits at. Required. |
y2 | number | Set it to shade the band between y and y2 instead of drawing a line. |
label | string | Text on the annotation. |
color | ChartColorValue | Annotation colour. |
dashed | boolean | Draw the line dashed. |
syncGroup is what turns a grid of separate metrics into one readable timeline: give every chart on the page the same group name and hovering one moves the crosshair on all of them.
Circular Charts
CircularChartProps extends the common options with staticDataset?: DonutRecord[] — a flat list of { label: string; value: number } rather than series.
| Props | Extra options |
|---|---|
DonutChartProps | centralLabel?: string, centralSubLabel?: string, arcWidth?: number |
PieChartProps | — |
RadialBarChartProps | hollowSize?: string, showTotal?: boolean |
Heatmap
HeatmapChartProps extends the common options directly — not the cartesian layer — with staticDataset?: ChartSeries[], shadeIntensity?: number and distributed?: boolean.
Series and Points
import type {
ChartCandlePoint,
ChartSeries,
ChartSeriesPoint,
} from "@antelopejs-private/cms/interfaces/cms-base/chart";
const series: ChartSeries[] = [
{
name: "Actions",
data: [
{ x: "2026-07-01", y: 12 },
{ x: "2026-07-02", y: 18 },
{ x: "2026-07-03", y: null },
],
},
];
| Type | Shape |
|---|---|
ChartSeries | name: string, data: Array<ChartSeriesPoint | ChartCandlePoint | ChartRangePoint | number>, type?: ChartType, color?: ChartColorValue |
ChartSeriesPoint | x: string | number | Date, y: number | null, label?: string |
ChartCandlePoint | x: string | number | Date, y: [number, number, number, number] |
ChartRangePoint | x: string | number | Date, y: [number, number] — the low and high bound a range area fills between |
DonutRecord | label: string, value: number |
A null y marks a gap. ChartSeries.type overrides the chart's own type for that series, which is what a mixed chart uses.
Colours and Formats
| Type | Values |
|---|---|
ColorName | "primary", "secondary", "success", "info", "warning", "error", "neutral", "accent" |
ChartColorValue | ColorName or a #…, rgb… or hsl… string |
ChartColor | ChartColorValue | ChartColorValue[] |
ComparisonStyle | "dashed", "solid", "dimmed" |
ValueFormat | "number", "currency", "percent", "compact" |
ColorName is the chart palette and is distinct from the Color enum in Shared Types: it adds accent and it is a string union rather than an enum. ValueFormat is used by the three card components rather than by the charts themselves.
Chart Events
| Namespace member | Value |
|---|---|
ChartEvents.SEGMENT_CLICK | "CmsComponent.Chart.SegmentClick" |
ChartEvents.POINT_CLICK | "CmsComponent.Chart.PointClick" |
ChartCard
ChartCard wraps a chart in a card that owns the title, the fetch URL and the delta display, and holds the chart as a child under the id "chart".
import { ChartArea, ChartCard } from "@antelopejs-private/cms/interfaces/cms-base";
const card = ChartCard({
title: "Revenue",
description: "Billed amount over the selected period",
icon: "i-ph-currency-eur",
fetchUrl: "/metrics/revenue",
periodScope: "finance",
valueFormat: "currency",
currencyCode: "EUR",
showDelta: true,
chart: ChartArea({ xaxisType: "datetime" }),
});
ChartCardBuilderOptions is ChartCardProps plus one required field, chart: Component. The chart is taken out of the options and attached as the card's child, so the serialized card options are exactly ChartCardProps.
ChartCardProps extends BaseComponentProps:
| Option | Type | Description |
|---|---|---|
title | string | Card title. Required; also the component display name. |
description | string | Card description. |
icon | string | Card icon. Defaults to "i-ph-chart-line" for the component metadata. |
fetchUrl | string | URL the card loads its data from. |
fetchUrlMethod | HttpMethod | Method for fetchUrl. |
periodScope | string | Id of the PeriodSelector to follow. |
valueFormat | ValueFormat | How the headline value is formatted. |
currencyCode | string | Currency for valueFormat: "currency". |
showDelta | boolean | Show the change against the comparison period. |
showLegend | boolean | Show the legend. |
primaryLabel | string | Label of the primary series. |
comparisonLabel | string | Label of the comparison series. |
KpiCard
KpiCard shows a single figure with an optional delta and sparkline.
import { KpiCard } from "@antelopejs-private/cms/interfaces/cms-base";
const denied = KpiCard({
title: "Denied",
icon: "i-ph-prohibit",
fetchUrl: "/ai/metrics/kpi/denied",
valueFormat: "compact",
invert: true,
compareLabel: "vs previous period",
});
KpiCardProps extends BaseComponentProps:
| Option | Type | Description |
|---|---|---|
title | string | Card title. Required; also the component display name. |
variant | "default" | "stat" | "stat" is the compact look: mono uppercase label, bare icon. |
description | string | Card description. |
icon | string | Card icon. Defaults to "i-ph-trend-up" for the component metadata. |
fetchUrl | string | URL the card loads its value from. |
fetchUrlMethod | HttpMethod | Method for fetchUrl. |
periodScope | string | Id of the PeriodSelector to follow. |
valueFormat | ValueFormat | How the value is formatted. |
currencyCode | string | Currency for valueFormat: "currency". |
showDelta | boolean | Show the change against the comparison period. |
showSparkline | boolean | Show the sparkline. |
sparklineAccent | ChartColorValue | "auto" | Sparkline colour. |
invert | boolean | Treat an increase as bad — for metrics where lower is better. |
compareLabel | string | Label next to the delta. |
staticValue | number | Inline value, as an alternative to fetchUrl. |
staticDelta | number | Inline delta. |
staticSparkline | number[] | Inline sparkline points. |
TopListCard
TopListCard shows a ranked list of items, each with a value and optionally a delta, a sparkline and an avatar.
import { TopListCard } from "@antelopejs-private/cms/interfaces/cms-base";
const topSkills = TopListCard({
title: "Top skills",
description: "Most-used tools over the selected period",
fetchUrl: "/ai/metrics/top-skills?limit=5",
periodScope: "ai-overview",
showRank: true,
highlightTopN: 3,
});
TopListCardProps extends BaseComponentProps:
| Option | Type | Description |
|---|---|---|
title | string | Card title. Required; also the component display name. |
description | string | Card description. |
fetchUrl | string | URL the card loads its items from. |
fetchUrlMethod | HttpMethod | Method for fetchUrl. |
periodScope | string | Id of the PeriodSelector to follow. |
valueFormat | ValueFormat | How each item's value is formatted. |
currencyCode | string | Currency for valueFormat: "currency". |
showRank | boolean | Show the rank number. |
highlightTopN | number | How many leading items are highlighted. |
rankColor | ChartColorValue | Colour of the rank marker. |
showDelta | boolean | Show each item's delta. |
showSparkline | boolean | Show each item's sparkline. |
sparklineAccent | ChartColorValue | "auto" | Sparkline colour. |
invert | boolean | Treat an increase as bad. |
badgeColor | ChartColorValue | Colour of the value badge. |
maxHeight | string | CSS max-height before the list scrolls. |
staticItems | TopListItem[] | Inline items, as an alternative to fetchUrl. |
emptyLabel | string | Text shown when there are no items. |
TopListItem is the item shape, the element type of staticItems:
| Field | Type | Description |
|---|---|---|
id | string | number | Item identifier. Required. |
title | string | Item label. Required. |
value | number | Item value. Required. |
description | string | Secondary line. |
delta | number | null | Change against the comparison period. |
sparkline | number[] | Sparkline points. |
icon | string | Leading icon. |
avatar | TopListItemAvatar | Leading avatar, { src: string; alt?: string }. |
to | string | Link target for the item. |
PeriodSelector
PeriodSelector owns a date range and a comparison mode, and publishes them under its id. Every widget carrying the same value in periodScope uses that range.
import { PeriodSelector } from "@antelopejs-private/cms/interfaces/cms-base";
const selector = PeriodSelector({
id: "finance",
align: "right",
defaultPreset: "this-month",
defaultComparison: "previous-year",
presets: ["this-month", "last-month", "ytd", "custom"],
presetLabels: { ytd: "Year to date" },
showRangeLabel: true,
});
PeriodSelectorProps extends BaseComponentProps:
| Option | Type | Description |
|---|---|---|
id | string | Scope identifier other widgets name in periodScope. Required. |
defaultPreset | PeriodPreset | Preset selected initially. |
defaultComparison | PeriodComparison | Comparison selected initially. |
presets | PeriodPreset[] | Presets offered. |
comparisons | PeriodComparison[] | Comparisons offered. |
presetLabels | Partial<Record<PeriodPreset, string>> | Overrides for preset labels. |
comparisonLabels | Partial<Record<PeriodComparison, string>> | Overrides for comparison labels. |
align | PeriodAlign | "left", "center" or "right". |
size | "xs" | "sm" | "md" | "lg" | "xl" | Control size. |
showRangeLabel | boolean | Show the resolved date range as text. |
variant | PeriodSelectorVariant | "default" or "segmented". |
PeriodPreset is "last-hour", "last-24h", "today", "yesterday", "last-7-days", "last-30-days", "last-90-days", "this-month", "last-month", "this-quarter", "last-quarter", "ytd", "last-year" or "custom". PeriodComparison is "none", "previous-period", "previous-year" or "custom". PeriodAlign is "left" | "center" | "right".
PeriodSelectorVariant is "default" | "segmented". segmented renders the presets as inline pills for one-click range switching; the custom range stays in its popover calendar either way.
Next Steps
- Layout and Containers - Grids, stacks, tabs, layouts and the custom-component escape hatch.