Skip to content

Widgets

Widgets are blocks of key figures, charts and short tables: the start page of a panel, figures above a list, own dashboards.

public function widgets(): array
{
return [
StatWidget::make('Open tasks')->icon('list-check')->url($this->url('tasks'))->permission('tasks.view')
->value(static fn (): int => (new TaskModel())->where('status', 'open')->countAllResults()),
ChartWidget::make('Deals by stage')->type(ChartWidget::BAR)->permission('deals.view')
->data(static fn (): array => ['labels' => ['Open', 'Won', 'Lost'], 'datasets' => [['label' => 'Deals', 'data' => [4, 7, 2]]]]),
TableWidget::make('Latest deals')->resource(DealResource::class)->columns(['title', 'stage', 'amount'])->limit(5),
];
}

All in Anvil\Widget:

Widget Shows Details
StatWidget one key figure with icon, e.g. “Open tasks: 12” Stat widget
GroupedStatsWidget several key figures in titled groups in one card Grouped stats
ChartWidget a bar, line, doughnut or pie chart Chart widget
TableWidget a few records of a resource, e.g. the latest deals Table widget
own widgets anything else Own widgets
Place Defined in Details
Dashboard of the panel Panel::widgets() Dashboard – arranged by every user
Above a list Resource::listWidgets() Above a list – optionally following search and filters
Own pages WidgetBoard Own dashboards
  • Computed when shown: values, chart data and table rows are computed in render(), only for widgets the user sees. Closures do not run for users without permission or for hidden widgets.
  • Permissions: permission() hides a widget from users without the permission. StatWidget, GroupedStatsWidget and ChartWidget without permission() are visible to every user of the panel; TableWidget follows the view permission of its resource.
  • Data: Anvil models are restricted to the current tenant, also in a widget. A bare model does not apply the scopeQuery() of a resource or its policies: query through the resource ($resource->query()), use a TableWidget (which does), or restrict the widget with permission().
  • Escaping: labels, values and data are escaped; charts receive their data as JSON, never as script (CSP).
  • Keys: layouts of users are stored by the key of a widget; give widgets whose label may change a key(), see Keys.

Widgets have no automatic refresh (polling) and no lazy loading: they are rendered with the page (dashboard, list) or with the answer of the list (fromList()). For figures that must update on their own, render a component and use htmx triggers, see Refreshing.