Widgets & charts
Dashboards are composed of widgets placed on a 12-column responsive grid. Each
widget has a type, a data source binding, and a grid position (x, y, w,
h).
Widget types
Section titled βWidget typesβ| Type | Purpose |
|---|---|
kpi | Single metric with optional comparison and sparkline |
chart | Data visualization (line, bar, pie, scatter, gauge, and more) |
table | Sortable, paginated data table |
text | Markdown or HTML labels and annotations |
filter | Interactive filter control (dropdown, date picker, etc.) |
html | Free-form HTML; scripts disabled by default |
image | Static image from blobs |
embed | iframe embed |
KPI widget
Section titled βKPI widgetβShows a single metric with context. The most-used widget type.
βββββββββββββββββββββββββββββββββ Label ββ $1,234,567 β² 15.2% ββ βββββ
ββ sparkline βββββββββββββββββββββββββββββββββdashboard.widgets.add('kpi', { value: 'total_revenue', label: 'Total Revenue', format: 'currency', formatOptions: { notation: 'compact' }, comparison: { value: 'prev_month_revenue', type: 'percent', invertColors: false, // set true when lower is better }, sparkline: { field: 'daily_revenue', type: 'area' }, size: 'lg', // 'sm' | 'md' | 'lg'}, { x: 0, y: 0, w: 4, h: 3 });Format values: 'number' | 'currency' | 'percent' | 'custom'
Recommended sizes:
| Size | Grid (wΓh) | Shows |
|---|---|---|
| Small | 3Γ2 | Value + label |
| Medium | 3Γ2 | Value + label + change |
| Large | 4Γ3 | Value + label + change + sparkline |
Chart widget
Section titled βChart widgetβVisualizes data trends and comparisons.
Chart types: line | bar | area | pie | donut | scatter |
heatmap | gauge | funnel | treemap
Choosing a chart type
Section titled βChoosing a chart typeβ| Question | Chart |
|---|---|
| How does it change over time? | line (continuous), bar (discrete periods) |
| How do things compare? | bar (vertical β€7 categories, horizontal for more or long labels) |
| Whatβs the composition? | pie / donut (β€6 slices) |
| Is there a relationship? | scatter |
| Whatβs progress toward a goal? | gauge |
| Whatβs the conversion flow? | funnel |
| Two-dimensional patterns? | heatmap |
// Line chartdashboard.widgets.add('chart', { chartType: 'line', xAxis: { field: 'date', type: 'time', label: 'Date' }, yAxis: { field: 'revenue', label: 'Revenue ($)', min: 0 }, series: [ { field: 'revenue', name: 'Actual', color: '#3b82f6' }, { field: 'target', name: 'Target', color: '#94a3b8' }, ], legend: { show: true, position: 'top' }, animation: true,}, { x: 0, y: 2, w: 6, h: 4 });Recommended minimum sizes:
| Chart type | Min grid (wΓh) | Ideal |
|---|---|---|
| Line / Area | 6Γ3 | 6Γ4 |
| Bar (vertical) | 4Γ3 | 6Γ4 |
| Bar (horizontal) | 6Γ4 | 8Γ5 |
| Pie / Donut | 4Γ4 | 4Γ4 |
| Scatter | 6Γ4 | 6Γ5 |
| Gauge | 3Γ3 | 4Γ3 |
Table widget
Section titled βTable widgetβSortable, filterable, paginated data table.
dashboard.widgets.add('table', { columns: [ { field: 'name', header: 'Customer', sortable: true }, { field: 'revenue', header: 'Revenue', format: 'currency', align: 'right', sortable: true }, { field: 'status', header: 'Status', format: 'badge' }, ], pageSize: 10, sortable: true, filterable: true, striped: true,}, { x: 0, y: 6, w: 12, h: 5 });Column format options: text | number | currency | percent | date |
boolean | link | image | badge
Tables should generally span the full 12 columns. Show 8β12 rows without scroll (5β6 row units); paginate at 10β25 items.
Text widget
Section titled βText widgetβMarkdown or HTML static content β section headers, annotations, instructions.
dashboard.widgets.add('text', { content: '## Sales Performance', contentType: 'markdown', // 'markdown' | 'html' align: 'left',}, { x: 0, y: 0, w: 12, h: 1 });Filter widget
Section titled βFilter widgetβInteractive filter controls are defined via dashboard.filters.addDefinition()
rather than widgets.add(). Filter types: select | multiselect |
daterange | numberrange | search.
dashboard.filters.addDefinition({ type: 'select', label: 'Region', options: [ { value: 'na', label: 'North America' }, { value: 'eu', label: 'Europe' }, { value: 'apac', label: 'Asia Pacific' }, ], affects: '*', // '*' = all widgets; or array of widget IDs});
dashboard.filters.addDefinition({ type: 'daterange', label: 'Period', defaultValue: { from: '2026-01-01', to: '2026-12-31' }, affects: ['chart-revenue', 'table-details'],});HTML widget
Section titled βHTML widgetβFree-form HTML for custom visualizations or embedded content.
dashboard.widgets.add('html', { content: '<div class="custom-viz" style="height:100%"><canvas id="globe"></canvas></div>', scripts: false, // enable only for trusted content}, { x: 0, y: 0, w: 6, h: 6 });Scripts are sandboxed and disabled by default. Sandbox iframe embeds.
Grid layout
Section titled βGrid layoutβDashboards use a 12-column grid. Widget positions are zero-indexed column and row coordinates.
βββ¬ββ¬ββ¬ββ¬ββ¬ββ¬ββ¬ββ¬ββ¬βββ¬βββ¬ββββ0β1β2β3β4β5β6β7β8β 9β10β11ββββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄ββ΄βββ΄βββ΄βββDefault row height: 80 px per row unit.
Standard sizes:
| Widget | w | h |
|---|---|---|
| KPI (small) | 3 | 2 |
| KPI (large) | 4 | 3 |
| Chart (half width) | 6 | 4 |
| Chart (full width) | 12 | 4β5 |
| Table | 12 | 5β6 |
| Filter bar | 12 | 1 |
Example: executive layout
Section titled βExample: executive layoutβ// KPI rowdashboard.widgets.add('kpi', kpiConfig1, { x: 0, y: 0, w: 3, h: 2 });dashboard.widgets.add('kpi', kpiConfig2, { x: 3, y: 0, w: 3, h: 2 });dashboard.widgets.add('kpi', kpiConfig3, { x: 6, y: 0, w: 3, h: 2 });dashboard.widgets.add('kpi', kpiConfig4, { x: 9, y: 0, w: 3, h: 2 });
// Charts rowdashboard.widgets.add('chart', trendConfig, { x: 0, y: 2, w: 6, h: 4 });dashboard.widgets.add('chart', breakdownConfig, { x: 6, y: 2, w: 6, h: 4 });
// Table rowdashboard.widgets.add('table', tableConfig, { x: 0, y: 6, w: 12, h: 5 });Responsive breakpoints
Section titled βResponsive breakpointsβThe layout field on DashboardMeta can be 'fixed' or 'responsive'. In
responsive mode the grid reflows at standard breakpoints:
| Viewport | Columns | Typical change |
|---|---|---|
| Desktop β₯1280 px | 12 | Full layout |
| Tablet 768β1279 px | 8 | KPIs 2-per-row, charts stack |
| Mobile β€767 px | 4 | KPIs 1-per-row, full-width charts |
Layout anti-patterns
Section titled βLayout anti-patternsβ- More than 4β6 KPIs overwhelm at a glance; group related metrics.
- Keep KPIs above the fold β viewers should not scroll to see key numbers.
- Vary widget sizes to signal importance; uniform sizing reads as undifferentiated.
- Use consistent column splits (6+6, 8+4, 4+4+4); avoid awkward proportions.
Repositioning widgets
Section titled βRepositioning widgetsβAfter adding, move or resize widgets via the layout manager:
dashboard.layout.move('kpi-revenue', 3, 0); // move to (3, 0)dashboard.layout.resize('chart-trend', 8, 4); // resize to 8 cols Γ 4 rowsdashboard.layout.update('table-deals', { x: 0, y: 9, w: 12, h: 5 });