Browse documentation

Widgets

Every widget builder and the options it accepts.

Widgets are the contents of a dashboard section, and of a drawer's widget tab. Each builder returns a WidgetConfig; every query runs on the server with a WidgetContext.

import { dashboard, metric, statGroup, table } from "@flowpanel/kit";
import { areaChart } from "@flowpanel/kit/charts";

export const overview = dashboard({
  path: "/",
  label: "Overview",
  dateRange: { preset: "last30d" },
  sections: [
    {
      label: "Revenue",
      widgets: [
        metric("MRR", async ({ db, dateRange }) => mrr(db, dateRange), {
          format: "currency",
          span: 3,
          drilldown: "/admin/invoices",
        }),
        areaChart("Revenue over time", async ({ db }) => revenueSeries(db), {
          x: "day",
          y: ["subscriptions", "one-off"],
          stacked: true,
          span: 9,
        }),
      ],
    },
  ],
});

WidgetContext

What every widget query receives.

Prop

Type

Shared option types

Span is 1 | 2 | 3 | 4 | 6 | 8 | 12 — the widget's width in the section's 12-column grid.

NumericFormat is "number" | "currency" | "percent" | "bytes" | "duration".

Tone is "default" | "accent" | "ok" | "warn" | "err" | "info" | "muted".

Every widget accepts realtime, a channel name or list. When one fires, that widget re-runs its query — the rest of the dashboard stays put.

metric

A single big-number widget.

export function metric(label: string, query: (ctx: WidgetContext) => Promise<number | string>, options?: MetricOptions): MetricWidget;

Prop

Type

icon is handed to the metric card as a React child and rendered verbatim. Metric icons are deliberately free-form: pass an emoji or a ligature your own icon font resolves; a Lucide name renders as literal text. This differs from resource, action and command icons, which use the serializable IconName registry described under resource icons.

MetricDelta

Prop

Type

table

A list-of-rows widget on a dashboard.

export function table<R = unknown>(options: TableWidgetOptions<R>): TableWidget;

Point it at a registered resource to reuse that resource's columns, or supply your own query and columns.

R is inferred from query, so columns is checked against the row that query returns — a misspelled column is a compile error. columns is RowKey<R>[], which is keyof R & string once R is known and plain string while it is not: without a query there is no row type to check against, and any column string is accepted.

Prop

Type

statGroup

A row of small stats (count + label) — denser than a grid of `metric()` cards.

export function statGroup(options: StatGroupOptions): StatGroupWidget;

Prop

Type

StatItem

Prop

Type

StatValue is string | number | boolean | bigint | Date | null | undefined. Keeping the literal side explicit preserves full WidgetContext autocomplete inside async value resolvers.

custom

Drop a fully-custom React component into a dashboard section.

export function custom<P>(Component: ComponentType<P>, props: P | ((ctx: WidgetContext) => Promise<P>), options?: CustomOptions): CustomWidget;

Renders your own component in the grid. props may be a value or a function resolved on the server per request, which is how you feed it query results.

Prop

Type

Charts

Chart builders live in @flowpanel/kit/charts, which is a separate entry point so the recharts bundle never loads for admins that use no charts.

import { areaChart, barChart, lineChart, pieChart } from "@flowpanel/kit/charts";

Each takes (label, query, options), where query returns an array of rows. The row type is inferred from query, so x / y (and category / value on a pie) must name keys of that row — a typo is a compile error. A query typed as unknown[] leaves them as plain strings.

ChartOptionsBase

Shared by area, bar and line charts.

Prop

Type

ChartBucket is "minute" | "hour" | "day" | "week" | "month" | "year" | "auto".

areaChart

export function areaChart<R = unknown>(label: string, query: (ctx: WidgetContext) => Promise<R[]>, options: AreaChartOptions<R>): AreaChartWidget;

Prop

Type

barChart

export function barChart<R = unknown>(label: string, query: (ctx: WidgetContext) => Promise<R[]>, options: BarChartOptions<R>): BarChartWidget;

Prop

Type

lineChart

export function lineChart<R = unknown>(label: string, query: (ctx: WidgetContext) => Promise<R[]>, options: LineChartOptions<R>): LineChartWidget;

Prop

Type

pieChart

export function pieChart<R = unknown>(label: string, query: (ctx: WidgetContext) => Promise<R[]>, options: PieChartOptions<R>): PieChartWidget;

Pie charts take category / value instead of x / y.

Prop

Type

Dashboards

Register a dashboard route under `/admin<path>`.

export function dashboard(config: DashboardConfig): DashboardConfig;

Register an arbitrary page under `/admin<path>` that renders a custom React component.

export function page(config: PageConfig): PageConfig;

Both are identity functions — they exist so the object literal is checked against its type at the call site and reads as a builder alongside resource() and queue().

Prop

Type

SectionConfig

Prop

Type

DateRangeConfig

Prop

Type

DateRangePreset is "today" | "yesterday" | "last7d" | "last30d" | "MTD" | "QTD" | "YTD".

ResolvedDateRange

Prop

Type

PageConfig

Prop

Type