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