[data-reveal]{opacity:1!important;transform:none!important}
Charts & widgets
Components

Charts & widgets

Dashboard blocks — KPI cards, chart cards, rankings, the period selector that scopes them, and the live toggle.

Dashboards are assembled from the blocks in this group: cards that headline one value or a ranking, charts that plot series and distributions, and a period selector that drives one date range across every widget bound to it. Each block fetches its own data from a backend route; you arrange the result in a Grid.

Run the demo template and open Components → Dashboard to explore this screen with deterministic sample data.

The blocks

KPI card

One headline figure with its variation and a sparkline.

Chart card

A framed chart with its headline value and comparison.

Top list

Ranked rows with their values, variations and bars.

Period selector

The date range every scoped widget follows.

Live toggle

Live / Pause for a monitoring page.

Charts

Thirteen chart types, from lines to heatmaps.

Compose a dashboard

Put one PeriodSelector at the top, then a Grid of GridRows holding the cards, all sharing its periodScope:

src/pages/sales.ts
import { PageController, RegisterPage, pagesCategory } from "@antelopejs/interface-dms/page";
import { PeriodSelector } from "@antelopejs/interface-dms/base/period-selector";
import { Grid, GridRow } from "@antelopejs/interface-dms/base/grid";
import { KpiCard } from "@antelopejs/interface-dms/base/kpi-card";
import { ChartCard } from "@antelopejs/interface-dms/base/chart-card";
import { ChartArea } from "@antelopejs/interface-dms/base/chart";
import { TopListCard } from "@antelopejs/interface-dms/base/top-list-card";

@RegisterPage()
export class SalesPage extends PageController("sales", {
  displayName: "$shop.sales.title",
  icon: "i-ph-chart-line-up",
  category: pagesCategory,
}) {
  static period = PeriodSelector({ id: "sales", defaultPreset: "last-30-days" });

  static dashboard = Grid()
    .child(
      "kpis",
      GridRow()
        .child("revenue", KpiCard({ title: "$shop.sales.revenue", fetchUrl: "/api/sales/revenue", periodScope: "sales", valueFormat: "currency", currencyCode: "EUR" }))
        .child("orders", KpiCard({ title: "$shop.sales.orders", fetchUrl: "/api/sales/orders", periodScope: "sales" })),
    )
    .child(
      "details",
      GridRow()
        .child("trend", ChartCard({ title: "$shop.sales.trend", fetchUrl: "/api/sales/series", periodScope: "sales", chart: ChartArea() }))
        .child("products", TopListCard({ title: "$shop.sales.top_products", fetchUrl: "/api/sales/top-products", periodScope: "sales" })),
    );
}

Shared options

The cards and the charts share the data options of every block (Block fundamentals): fetchUrl, fetchUrlMethod, periodScope and realtimeTopic. The three cards also share:

OptionTypePurpose
valueFormat"number" | "currency" | "percent" | "compact"How values are written.
currencyCodestringISO code used when valueFormat is currency.
valuePrecisionnumber | "native"Fixed fraction digits, or the Intl defaults. Code only.
showDeltabooleanThe change-versus-comparison badge.

Value precision

valuePrecision opts into fixed fraction digits (a non-negative integer Intl.NumberFormat supports) or "native" for the Intl defaults. Native currency formatting follows the currency's minor units: EUR uses two digits, JPY zero, KWD three. It changes display only, never the amounts.

Without it, currency rounds to whole units, percent and compact use at most one fraction digit, and number uses the Intl defaults. ChartCard passes the policy to its headline, its previous value and its chart's value axis and tooltip. Delta badges keep their own one-decimal policy.

src/pages/usage.ts
ChartCard({
  title: "Spend",
  fetchUrl: "/api/usage/spend",
  valueFormat: "currency",
  currencyCode: "EUR",
  valuePrecision: "native",
  chart: ChartLine(),
});
A delta is always a change in percent: 12.5 reads +12.5 %, for a value going from 100 to 112.5. Never send the 0.125 ratio.

Next steps

Period filtering

How a route reads the period a selector sends.

Live pages

Refresh dashboards in real time without flooding them.