| title | Plugin Dashboard |
|---|
import { InteractiveDemo } from '@/app/components/InteractiveDemo'; import { PluginLoader } from '@/app/components/PluginLoader';
Dashboard layouts and metric widgets for creating beautiful dashboards with KPIs, charts, and statistics.
npm install @object-ui/plugin-dashboard<PluginLoader plugins={['dashboard']}>
- Dashboard Layouts - Responsive grid-based layouts
- Metric Cards - Display KPIs with trends and icons
- Widget System - Modular widget architecture
- Customizable - Full Tailwind CSS styling support
{
type: 'dashboard',
widgets: Widget[],
columns?: number, // Grid columns (default: 3)
gap?: number, // Gap between widgets
className?: string
}
{
type: 'metric-card',
title: string,
value: string | number,
icon?: string, // Lucide icon name
trend?: 'up' | 'down' | 'neutral',
trendValue?: string,
description?: string,
className?: string
}
import '@object-ui/plugin-dashboard';
import { dashboardComponents } from '@object-ui/plugin-dashboard';
import { ComponentRegistry } from '@object-ui/core';
Object.entries(dashboardComponents).forEach(([type, component]) => {
ComponentRegistry.register(type, component);
});
{
"type": "dashboard",
"columns": 4,
"gap": 6,
"widgets": [
{
"type": "metric-card",
"title": "Total Sales",
"value": "$123,456",
"icon": "shopping-cart",
"trend": "up",
"trendValue": "+15%"
},
{
"type": "metric-card",
"title": "New Customers",
"value": "856",
"icon": "user-plus",
"trend": "up",
"trendValue": "+22%"
},
{
"type": "metric-card",
"title": "Bounce Rate",
"value": "2.4%",
"icon": "trending-down",
"trend": "down",
"trendValue": "-5%"
},
{
"type": "metric-card",
"title": "Avg. Order Value",
"value": "$144.20",
"icon": "dollar-sign",
"trend": "up",
"trendValue": "+8%"
}
]
}{
"type": "dashboard",
"widgets": [
{
"type": "metric-card",
"title": "Total Revenue",
"value": "$123,456"
},
{
"type": "card",
"title": "Sales Trend",
"body": {
"type": "line-chart",
"data": [],
"height": 300
}
}
]
}A dashboard can declare top-level filters — a date range plus any number of
select / text filters — whose values drive every bound widget at once. Filter
values live as dashboard-level variables; each widget declares which of its
own fields a filter binds to via filterBindings, and the dashboard merges
the active values into each bound widget's inline query (AND-combined with
the widget's own filter).
{
"type": "dashboard",
"dateRange": { "field": "created_at", "defaultRange": "last_30_days", "allowCustomRange": true },
"globalFilters": [
{ "name": "region", "field": "region", "label": "Region", "type": "select", "options": ["EMEA", "APAC", "AMER"] }
],
"widgets": [
{ "id": "w1", "type": "bar", "object": "invoices", "aggregate": "count" },
{
"id": "w2", "type": "line", "object": "accounts", "aggregate": "count",
"filterBindings": { "dateRange": "signed_at", "region": "sales_region" }
},
{
"id": "w3", "type": "metric", "object": "invoices", "aggregate": "count",
"filterBindings": { "region": false }
}
]
}Binding rules, in precedence order:
filterBindings[name]as a string — apply the filter to that field.filterBindings[name]: false— opt this widget out.- Legacy
targetWidgetson the filter — when set, only listed widget ids get the default binding (an explicitfilterBindingsentry still wins). - Otherwise the filter applies to its own
field(the built-in date range defaults todateRange.field ?? 'created_at').
Date presets stay symbolic (date-macro tokens such as {30_days_ago}) until
query time. Dataset-bound widgets receive the merged filter through the
dataset query's runtimeFilter. Static-data widgets (inline data arrays)
have no query to scope and are not filtered. Filter values are also readable
in widget expressions as page.<name>.
For a step-by-step tutorial — filter types, optionsFrom dynamic options,
page.* expression usage, and known limitations with workarounds — see the
Dashboard-Level Filters guide. The schema
catalog ships runnable variants under plugin-dashboard/filtered-dashboard*
(dynamic options, filter types, dataset widgets, targetWidgets, date
presets).
import type { DashboardSchema, MetricCardSchema } from '@object-ui/plugin-dashboard';
const dashboard: DashboardSchema = {
type: 'dashboard',
columns: 3,
widgets: [...]
};
type: 'table' widgets bound to an objectName infer the renderer for
each cell from the object's field type — Badges for select, expanded
display name for lookup/user/owner, formatted currency/percent/date
for numeric fields, and so on. Lookup columns are auto-expanded server-side
via $expand, so you don't see raw FK ids. See
@object-ui/plugin-dashboard README
for the full mapping table and an example.
MIT