Documentation Index Fetch the complete documentation index at: https://mintlify.com/filamentphp/filament/llms.txt
Use this file to discover all available pages before exploring further.
Introduction
Filament provides powerful chart widgets that allow you to display real-time, interactive charts using Chart.js. These widgets are perfect for visualizing trends, comparing data sets, and presenting analytics in an engaging way.
Chart widgets support multiple chart types including line, bar, pie, doughnut, radar, polar area, bubble, and scatter charts.
Generate a chart widget using the Artisan command:
php artisan make:filament-widget BlogPostsChart --chart
This creates a widget class that extends ChartWidget:
namespace App\Filament\Widgets ;
use Filament\Widgets\ ChartWidget ;
class BlogPostsChart extends ChartWidget
{
protected ? string $heading = 'Blog Posts' ;
protected function getData () : array
{
return [
'datasets' => [
[
'label' => 'Blog posts created' ,
'data' => [ 0 , 10 , 5 , 2 , 21 , 32 , 45 , 74 , 65 , 45 , 77 , 89 ],
],
],
'labels' => [ 'Jan' , 'Feb' , 'Mar' , 'Apr' , 'May' , 'Jun' , 'Jul' , 'Aug' , 'Sep' , 'Oct' , 'Nov' , 'Dec' ],
];
}
protected function getType () : string
{
return 'line' ;
}
}
Available Chart Types
Filament supports all Chart.js chart types. Set the chart type by returning the appropriate string from the getType() method:
Line Chart 'line' - Display data as connected points
Bar Chart 'bar' - Display data as vertical bars
Pie Chart 'pie' - Display data as circular segments
Doughnut Chart 'doughnut' - Display data as a ring chart
Radar Chart 'radar' - Display multivariate data on axes
Polar Area Chart 'polarArea' - Display data as circular sectors
Bubble Chart 'bubble' - Display three-dimensional data
Scatter Chart 'scatter' - Display data as points on x/y axes
Chart Type Examples
// Line chart
protected function getType () : string
{
return 'line' ;
}
// Bar chart
protected function getType () : string
{
return 'bar' ;
}
// Pie chart
protected function getType () : string
{
return 'pie' ;
}
Refer to the Chart.js documentation for detailed information about each chart type and data format requirements.
Chart Data Structure
The getData() method returns an array with datasets and labels:
protected function getData () : array
{
return [
'datasets' => [
[
'label' => 'Sales' ,
'data' => [ 1200 , 1900 , 3000 , 5000 , 2400 , 3200 ],
],
],
'labels' => [ 'Jan' , 'Feb' , 'Mar' , 'Apr' , 'May' , 'Jun' ],
];
}
Multiple Datasets
Display multiple datasets on the same chart:
protected function getData () : array
{
return [
'datasets' => [
[
'label' => 'Sales' ,
'data' => [ 1200 , 1900 , 3000 , 5000 , 2400 , 3200 ],
'backgroundColor' => '#36A2EB' ,
],
[
'label' => 'Revenue' ,
'data' => [ 1000 , 1700 , 2800 , 4800 , 2200 , 3000 ],
'backgroundColor' => '#FF6384' ,
],
],
'labels' => [ 'Jan' , 'Feb' , 'Mar' , 'Apr' , 'May' , 'Jun' ],
];
}
Generating Data from Eloquent Models
Filament recommends using the flowframe/laravel-trend package to generate chart data from Eloquent models:
composer require flowframe/laravel-trend
Then use it in your widget:
use Flowframe\Trend\ Trend ;
use Flowframe\Trend\ TrendValue ;
use App\Models\ BlogPost ;
protected function getData () : array
{
$data = Trend :: model ( BlogPost :: class )
-> between (
start : now () -> startOfYear (),
end : now () -> endOfYear (),
)
-> perMonth ()
-> count ();
return [
'datasets' => [
[
'label' => 'Blog posts' ,
'data' => $data -> map ( fn ( TrendValue $value ) => $value -> aggregate ),
],
],
'labels' => $data -> map ( fn ( TrendValue $value ) => $value -> date ),
];
}
Advanced Trend Queries
// Count by week
$data = Trend :: model ( Order :: class )
-> between ( start : now () -> subWeeks ( 12 ), end : now ())
-> perWeek ()
-> count ();
// Sum by day
$data = Trend :: model ( Order :: class )
-> between ( start : now () -> subDays ( 30 ), end : now ())
-> perDay ()
-> sum ( 'total' );
// Average by month
$data = Trend :: model ( Customer :: class )
-> between ( start : now () -> subYear (), end : now ())
-> perMonth ()
-> average ( 'satisfaction_score' );
Chart Colors
Customize chart colors using the $color property:
protected string $color = 'success' ;
Available colors match Filament’s color system: primary, success, warning, danger, info, gray.
Custom Dataset Colors
For more control, set colors directly in the dataset:
protected function getData () : array
{
return [
'datasets' => [
[
'label' => 'Revenue' ,
'data' => [ 1200 , 1900 , 3000 , 5000 , 2400 ],
'backgroundColor' => '#10B981' ,
'borderColor' => '#059669' ,
],
],
'labels' => [ 'Jan' , 'Feb' , 'Mar' , 'Apr' , 'May' ],
];
}
Chart Filters
Basic Select Filter
Add a filter dropdown to change the chart data:
public ? string $filter = 'today' ;
protected function getFilters () : ? array
{
return [
'today' => 'Today' ,
'week' => 'Last week' ,
'month' => 'Last month' ,
'year' => 'This year' ,
];
}
protected function getData () : array
{
$activeFilter = $this -> filter ;
// Generate data based on $activeFilter
$data = match ( $activeFilter ) {
'today' => $this -> getDataForToday (),
'week' => $this -> getDataForWeek (),
'month' => $this -> getDataForMonth (),
'year' => $this -> getDataForYear (),
};
return [
'datasets' => [
[
'label' => 'Revenue' ,
'data' => $data ,
],
],
'labels' => $this -> getLabelsForFilter ( $activeFilter ),
];
}
Custom Filter Schema
Build more complex filters using form components:
use Filament\Forms\Components\ DatePicker ;
use Filament\Forms\Components\ Select ;
use Filament\Schemas\ Schema ;
use Filament\Widgets\ChartWidget\Concerns\ HasFiltersSchema ;
class RevenueChart extends ChartWidget
{
use HasFiltersSchema ;
public function filtersSchema ( Schema $schema ) : Schema
{
return $schema -> components ([
DatePicker :: make ( 'startDate' )
-> default ( now () -> subDays ( 30 )),
DatePicker :: make ( 'endDate' )
-> default ( now ()),
Select :: make ( 'category' )
-> options ([
'all' => 'All Categories' ,
'electronics' => 'Electronics' ,
'clothing' => 'Clothing' ,
]),
]);
}
protected function getData () : array
{
$startDate = $this -> filters [ 'startDate' ] ?? null ;
$endDate = $this -> filters [ 'endDate' ] ?? null ;
$category = $this -> filters [ 'category' ] ?? 'all' ;
// Use filters to generate data
return [
// ...
];
}
}
Deferred Filters
Prevent chart updates until the user clicks “Apply”:
use Filament\Widgets\ChartWidget\Concerns\ HasFiltersSchema ;
class RevenueChart extends ChartWidget
{
use HasFiltersSchema ;
protected bool $hasDeferredFilters = true ;
// ...
}
With deferred filters:
Chart displays using default filter values on page load
Changes only apply when the user clicks “Apply”
A “Reset” link restores default values
Better performance for complex queries
Customizing Filter Actions
use Filament\Actions\ Action ;
public function filtersApplyAction ( Action $action ) : Action
{
return $action
-> label ( 'Update Chart' )
-> color ( 'success' );
}
public function filtersResetAction ( Action $action ) : Action
{
return $action
-> label ( 'Clear Filters' )
-> color ( 'danger' );
}
Live Updating (Polling)
Charts refresh every 5 seconds by default. Customize the polling interval:
// Refresh every 10 seconds
protected ? string $pollingInterval = '10s' ;
// Refresh every minute
protected ? string $pollingInterval = '60s' ;
// Disable polling
protected ? string $pollingInterval = null ;
Chart Height
Limit the maximum height of charts:
protected ? string $maxHeight = '300px' ;
This prevents charts from becoming too large on larger screens.
Chart Options
Customize Chart.js configuration using the $options property:
protected ? array $options = [
'plugins' => [
'legend' => [
'display' => false ,
],
],
'scales' => [
'y' => [
'beginAtZero' => true ,
],
],
];
Dynamic Options
Use the getOptions() method for dynamic configuration:
protected function getOptions () : array
{
return [
'plugins' => [
'legend' => [
'display' => $this -> showLegend ,
],
],
];
}
JavaScript Callbacks
Use RawJs for JavaScript callbacks:
use Filament\Support\ RawJs ;
protected function getOptions () : RawJs
{
return RawJs :: make ( <<< JS
{
scales : {
y : {
ticks : {
callback : ( value ) => '€' + value ,
},
},
},
}
JS );
}
Chart Heading and Description
Set the heading and description:
protected ? string $heading = 'Monthly Revenue' ;
protected ? string $description = 'Revenue trend for the current year' ;
Or use methods for dynamic values:
public function getHeading () : ? string
{
return 'Revenue - ' . now () -> format ( 'F Y' );
}
public function getDescription () : ? string
{
return 'Last updated ' . now () -> diffForHumans ();
}
Making Charts Collapsible
Allow users to collapse charts to save space:
protected bool $isCollapsible = true ;
Lazy Loading
By default, charts are lazy-loaded. Disable if needed:
protected static bool $isLazy = false ;
Using Chart.js Plugins
Extend Chart.js functionality with plugins.
Step 1: Install the Plugin
npm install chartjs-plugin-datalabels --save-dev
Step 2: Create a JavaScript File
Create resources/js/filament-chart-js-plugins.js:
import ChartDataLabels from 'chartjs-plugin-datalabels'
window . filamentChartJsPlugins ??= []
window . filamentChartJsPlugins . push ( ChartDataLabels )
For global plugins:
window . filamentChartJsGlobalPlugins ??= []
window . filamentChartJsGlobalPlugins . push ( ChartDataLabels )
Step 3: Build with Vite
Update vite.config.js:
export default defineConfig ({
plugins: [
laravel ({
input: [
'resources/css/app.css' ,
'resources/js/app.js' ,
'resources/js/filament-chart-js-plugins.js' ,
],
}),
] ,
}) ;
Build:
Step 4: Register in Filament
In a service provider:
use Filament\Support\Assets\ Js ;
use Filament\Support\Facades\ FilamentAsset ;
use Illuminate\Support\Facades\ Vite ;
public function boot () : void
{
FilamentAsset :: register ([
Js :: make (
'chart-js-plugins' ,
Vite :: asset ( 'resources/js/filament-chart-js-plugins.js' )
) -> module (),
]);
}
Best Practices
Choose Appropriate Chart Types : Use line charts for trends, bar charts for comparisons, pie charts for proportions
Keep Data Manageable : Limit data points to prevent overcrowded charts (typically 12-20 points max)
Use Meaningful Labels : Provide clear axis labels and legends
Color Consistency : Use consistent colors across dashboards for related data
Optimize Queries : Cache expensive database queries, especially with polling enabled
Responsive Design : Test charts on mobile devices
Filter Validation : When using filters, ensure data is valid before querying
Tooltip Enhancement : Customize tooltips to show relevant information
Accessibility : Ensure charts have appropriate labels and descriptions
Performance : Use deferred filters for complex queries to prevent excessive reloads
Common Chart Patterns
Revenue Over Time
use Flowframe\Trend\ Trend ;
use Flowframe\Trend\ TrendValue ;
protected function getData () : array
{
$data = Trend :: model ( Order :: class )
-> between ( start : now () -> subMonths ( 12 ), end : now ())
-> perMonth ()
-> sum ( 'total' );
return [
'datasets' => [
[
'label' => 'Revenue' ,
'data' => $data -> map ( fn ( TrendValue $value ) => $value -> aggregate ),
'backgroundColor' => '#10B981' ,
'borderColor' => '#059669' ,
],
],
'labels' => $data -> map ( fn ( TrendValue $value ) => $value -> date ),
];
}
Status Distribution
use App\Models\ Order ;
protected function getData () : array
{
$statuses = Order :: query ()
-> selectRaw ( 'status, count(*) as count' )
-> groupBy ( 'status' )
-> pluck ( 'count' , 'status' );
return [
'datasets' => [
[
'data' => $statuses -> values (),
'backgroundColor' => [ '#10B981' , '#F59E0B' , '#EF4444' , '#6B7280' ],
],
],
'labels' => $statuses -> keys (),
];
}
protected function getType () : string
{
return 'pie' ;
}
Comparison Chart
protected function getData () : array
{
return [
'datasets' => [
[
'label' => '2024' ,
'data' => [ 12 , 19 , 30 , 50 , 24 , 32 ],
'backgroundColor' => '#3B82F6' ,
],
[
'label' => '2023' ,
'data' => [ 10 , 17 , 28 , 48 , 22 , 30 ],
'backgroundColor' => '#9CA3AF' ,
],
],
'labels' => [ 'Jan' , 'Feb' , 'Mar' , 'Apr' , 'May' , 'Jun' ],
];
}
protected function getType () : string
{
return 'bar' ;
}
Next Steps