Try Live
Add Docs
Rankings
Pricing
Enterprise
Docs
Install
Install
Docs
Pricing
Enterprise
More...
More...
Try Live
Rankings
Add Docs
Filament Apex Charts
https://github.com/leandrocfe/filament-apex-charts
Admin
Filament Apex Charts is an integration that allows developers to easily add various types of Apex
...
Tokens:
10,790
Snippets:
105
Trust Score:
9.6
Update:
2 weeks ago
Context
Skills
Chat
Benchmark
86.5
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Filament Apex Charts Filament Apex Charts is a Laravel package that integrates the [ApexCharts](https://apexcharts.com/) JavaScript library into [Filament](https://filamentphp.com/) admin panels as first-class Livewire widget components. It supports Filament v5 (and also v2–v4 via separate tags) and provides 19 chart types — including line, bar, area, pie, donut, heatmap, scatter, radialBar, candlestick, treemap, funnel, and more. The package is registered as a Filament plugin and publishes Alpine.js-powered chart components, Blade views, and language files into the host Laravel application. Every chart is created by extending the `ApexChartWidget` base class and implementing a single `getOptions(): array` method whose structure mirrors the [ApexCharts JavaScript options object](https://apexcharts.com/docs/options) exactly. Widget behaviour — polling intervals, deferred loading, dark mode, filter forms, loading indicators, collapsible headers, footers, and raw JavaScript formatter callbacks — are all controlled through properties and override-able methods on the same class, making chart widgets self-contained Livewire components that can be dropped into any Filament panel dashboard or resource page. --- ## Installation & Plugin Registration Install via Composer and register `FilamentApexChartsPlugin` on every Filament panel that should render charts. ```php // Terminal composer require leandrocfe/filament-apex-charts:"^5.0" // app/Providers/Filament/AdminPanelProvider.php use Leandrocfe\FilamentApexCharts\FilamentApexChartsPlugin; use Filament\Panel; public function panel(Panel $panel): Panel { return $panel ->plugins([ FilamentApexChartsPlugin::make(), ]); } ``` --- ## Artisan Generator — `make:filament-apex-charts` Scaffolds a new widget class pre-filled with a chosen chart type stub, resolved into the correct Filament panel widget directory. ```bash # Interactive (prompts for name, chart type, panel, and optional resource) php artisan make:filament-apex-charts BlogPostsChart # The command will ask: # 1. Chart name → BlogPostsChart # 2. Chart type → Line | Bar | Area | Pie | Donut | Column | Boxplot | # Bubble | Candlestick | Heatmap | Mixed-LineAndColumn | # PolarArea | Radar | Radialbar | RangeArea | Scatter | # TimelineRangeBars | Treemap | Funnel | Empty # 3. Destination panel → [admin] panel (or alongside Livewire components) # 4. Resource (optional) → BlogPostResource # Output: app/Filament/Widgets/BlogPostsChart.php ``` --- ## `ApexChartWidget` — Base Widget Class `Leandrocfe\FilamentApexCharts\Widgets\ApexChartWidget` is the abstract base all chart widgets extend. It wires together Livewire, Filament's polling, Alpine.js, and all the concern traits listed below. Override `getOptions()` to supply chart data; call `updateOptions()` from any Livewire action to push new data to the browser without a full page reload. ```php namespace App\Filament\Widgets; use Leandrocfe\FilamentApexCharts\Widgets\ApexChartWidget; use Leandrocfe\FilamentApexCharts\Enums\ApexChartTypeEnum; class BlogPostsChart extends ApexChartWidget { // Unique DOM id for this chart instance protected static ?string $chartId = 'blogPostsChart'; // Displayed in the widget card header protected static ?string $heading = 'Blog Posts'; protected static ?string $subheading = 'Posts published per month'; protected function getOptions(): array { $data = \App\Models\Post::query() ->selectRaw('MONTH(created_at) as month, COUNT(*) as total') ->whereYear('created_at', now()->year) ->groupBy('month') ->pluck('total', 'month') ->toArray(); return [ 'chart' => [ 'type' => ApexChartTypeEnum::Bar, 'height' => 300, ], 'series' => [ ['name' => 'Posts', 'data' => array_values($data)], ], 'xaxis' => [ 'categories' => ['Jan','Feb','Mar','Apr','May','Jun', 'Jul','Aug','Sep','Oct','Nov','Dec'], ], 'colors' => ['#6366f1'], ]; } } ``` --- ## `ApexChartTypeEnum` A backed string enum that maps friendly PHP names to the string values required by the ApexCharts `chart.type` option, preventing typos and enabling IDE autocompletion. ```php use Leandrocfe\FilamentApexCharts\Enums\ApexChartTypeEnum; // All available cases: ApexChartTypeEnum::Area // 'area' ApexChartTypeEnum::Bar // 'bar' ApexChartTypeEnum::Boxplot // 'boxPlot' ApexChartTypeEnum::Bubble // 'bubble' ApexChartTypeEnum::Candlestick // 'candlestick' ApexChartTypeEnum::Column // 'column' ApexChartTypeEnum::Donut // 'donut' ApexChartTypeEnum::Funnel // 'funnel' ApexChartTypeEnum::Heatmap // 'heatmap' ApexChartTypeEnum::Line // 'line' ApexChartTypeEnum::Pie // 'pie' ApexChartTypeEnum::PolarArea // 'polarArea' ApexChartTypeEnum::Radar // 'radar' ApexChartTypeEnum::Radialbar // 'radialBar' ApexChartTypeEnum::RangeArea // 'rangeArea' ApexChartTypeEnum::Scatter // 'scatter' ApexChartTypeEnum::TimelineRangeBars // 'rangeBar' ApexChartTypeEnum::Treemap // 'treemap' ApexChartTypeEnum::Empty // '' // Usage inside getOptions() 'chart' => ['type' => ApexChartTypeEnum::Line, 'height' => 300], ``` --- ## `getOptions(): array` The single required method on every widget. Returns a PHP array that is serialised directly to the ApexCharts JavaScript options object. Every key documented at <https://apexcharts.com/docs/options> is valid here. ```php // Line chart with smooth curve protected function getOptions(): array { return [ 'chart' => ['type' => 'line', 'height' => 300], 'series' => [ ['name' => 'Revenue', 'data' => [2, 4, 6, 10, 14, 7, 2, 9, 10, 15, 13, 18]], ], 'xaxis' => [ 'categories' => ['Jan','Feb','Mar','Apr','May','Jun', 'Jul','Aug','Sep','Oct','Nov','Dec'], 'labels' => ['style' => ['colors' => '#9ca3af', 'fontWeight' => 600]], ], 'yaxis' => ['labels' => ['style' => ['colors' => '#9ca3af']]], 'colors' => ['#6366f1'], 'stroke' => ['curve' => 'smooth'], ]; } // Pie chart (series is a flat array, labels is a top-level key) protected function getOptions(): array { return [ 'chart' => ['type' => 'pie', 'height' => 300], 'series' => [2, 4, 6, 10, 14], 'labels' => ['Jan', 'Feb', 'Mar', 'Apr', 'May'], 'legend' => ['labels' => ['colors' => '#9ca3af', 'fontWeight' => 600]], ]; } // Area chart protected function getOptions(): array { return [ 'chart' => ['type' => 'area', 'height' => 300], 'series' => [['name' => 'Visitors', 'data' => [7,4,6,10,14,7,5,9,10,15,13,18]]], 'xaxis' => ['categories' => ['Jan','Feb','Mar','Apr','May','Jun', 'Jul','Aug','Sep','Oct','Nov','Dec']], 'colors' => ['#6366f1'], 'stroke' => ['curve' => 'smooth'], 'dataLabels' => ['enabled' => false], ]; } ``` --- ## `updateOptions(): void` Triggers a live browser update of the chart's data without a full Livewire re-render. Call this after mutating any state that `getOptions()` depends on (e.g., after a filter change). ```php use Leandrocfe\FilamentApexCharts\Widgets\ApexChartWidget; class SalesChart extends ApexChartWidget { protected static ?string $chartId = 'salesChart'; protected static ?string $heading = 'Sales'; public string $period = 'monthly'; // Livewire action — wire:click="setPeriod('weekly')" public function setPeriod(string $period): void { $this->period = $period; $this->updateOptions(); // pushes new getOptions() result to ApexCharts } protected function getOptions(): array { $data = $this->period === 'weekly' ? [10, 20, 30, 40, 50, 60, 70] : [7, 4, 6, 10, 14, 7, 5, 9, 10, 15, 13, 18]; return [ 'chart' => ['type' => 'bar', 'height' => 300], 'series' => [['name' => 'Sales', 'data' => $data]], ]; } } ``` --- ## `extraJsOptions(): ?RawJs` Merges raw JavaScript (including closures) into the chart options at render time. Use this for formatter functions that cannot be expressed as PHP strings. ```php use Filament\Support\RawJs; protected function extraJsOptions(): ?RawJs { return RawJs::make(<<<'JS' { yaxis: { labels: { formatter: function (val) { return '$' + val.toLocaleString() } } }, tooltip: { x: { formatter: function (val) { return val + '/24' } } }, dataLabels: { enabled: true, formatter: function (val, opt) { return opt.w.globals.labels[opt.dataPointIndex] + ': $' + val }, dropShadow: { enabled: true } } } JS); } ``` --- ## Widget Header — `HasHeader` Trait Controls the card title, subtitle, and collapsibility of the widget. All properties have corresponding override methods. ```php class RevenueChart extends ApexChartWidget { protected static ?string $chartId = 'revenueChart'; // Static property approach protected static ?string $heading = 'Monthly Revenue'; protected static ?string $subheading = 'Compared to last year'; protected static bool $isCollapsible = true; // Or override the methods for dynamic values: protected function getHeading(): string { return 'Revenue — ' . now()->year; } protected function getSubheading(): string { return 'Total: $' . number_format(\App\Models\Order::sum('total')); } protected function isCollapsible(): bool { return auth()->user()->prefersCollapsedWidgets(); } protected function getOptions(): array { return ['chart' => ['type' => 'line', 'height' => 250], 'series' => []]; } } ``` --- ## Widget Footer — `HasFooter` Trait Renders an optional footer below the chart. Accepts a plain string, an `Htmlable` instance (e.g., `HtmlString`), or a Blade view. ```php use Illuminate\Contracts\Support\Htmlable; use Illuminate\Contracts\View\View; use Illuminate\Support\HtmlString; class StatsChart extends ApexChartWidget { protected static ?string $chartId = 'statsChart'; // Plain string protected static ?string $footer = 'Data refreshed every 5 seconds.'; // Or a dynamic HTML string: protected function getFooter(): null|string|Htmlable|View { $avg = \App\Models\Sale::avg('amount'); return new HtmlString( '<p class="text-sm text-gray-500">Average sale: <strong>$' . number_format($avg, 2) . '</strong></p>' ); } // Or a Blade view: // protected function getFooter(): View // { // return view('widgets.chart-footer', ['period' => 'Q1 2025']); // } protected function getOptions(): array { return ['chart' => ['type' => 'bar', 'height' => 250], 'series' => []]; } } ``` --- ## Content Height — `HasContentHeight` Trait Sets a fixed pixel height for the chart content area, overriding the height defined inside `getOptions()['chart']['height']` at the widget wrapper level. ```php class TallChart extends ApexChartWidget { protected static ?string $chartId = 'tallChart'; // Static property (pixels) protected static ?int $contentHeight = 500; // Or via method: protected function getContentHeight(): ?int { return request()->is('*/dashboard') ? 400 : 250; } protected function getOptions(): array { return [ 'chart' => ['type' => 'area', 'height' => $this->getContentHeight() ?? 300], 'series' => [['name' => 'Data', 'data' => [1,3,5,7,9]]], ]; } } ``` --- ## Dark Mode — `HasDarkMode` Trait Dark mode is enabled by default. Disable it per widget via a static property, or manually control the ApexCharts theme inside `getOptions()`. ```php class LightOnlyChart extends ApexChartWidget { protected static ?string $chartId = 'lightChart'; // Disable automatic dark mode handling protected static bool $darkMode = false; // Or force a specific theme inside getOptions(): protected function getOptions(): array { return [ 'theme' => ['mode' => 'light'], // or 'dark' 'chart' => ['type' => 'bar', 'height' => 300], 'series' => [['name' => 'Data', 'data' => [5, 10, 15]]], ]; } } ``` --- ## Deferred Loading — `CanDeferLoading` Trait Delays data fetching until after the page is rendered. The widget displays a loading indicator immediately, then fires a Livewire request to fetch chart data. Ideal for slow queries. ```php class HeavyQueryChart extends ApexChartWidget { protected static ?string $chartId = 'heavyChart'; protected static bool $deferLoading = true; protected static ?string $loadingIndicator = 'Loading chart data…'; protected function getOptions(): array { // Guard: return empty array while still loading if (! $this->readyToLoad) { return []; } // Expensive query runs only after the page has loaded $data = \App\Models\AnalyticsEvent::query() ->selectRaw('DATE(created_at) as date, COUNT(*) as hits') ->groupBy('date') ->orderBy('date') ->limit(30) ->pluck('hits', 'date'); return [ 'chart' => ['type' => 'line', 'height' => 300], 'series' => [['name' => 'Page Hits', 'data' => $data->values()->toArray()]], 'xaxis' => ['categories' => $data->keys()->toArray()], ]; } } ``` --- ## Loading Indicator — `HasLoadingIndicator` Trait Customises the loading placeholder shown while data is being fetched (used with deferred loading or polling). ```php use Illuminate\Contracts\View\View; class CustomLoadingChart extends ApexChartWidget { protected static ?string $chartId = 'customLoadingChart'; protected static bool $deferLoading = true; // Simple string protected static ?string $loadingIndicator = 'Fetching data…'; // Or a Blade view: protected function getLoadingIndicator(): null|string|View { return view('widgets.chart-skeleton'); // resources/views/widgets/chart-skeleton.blade.php: // <div class="animate-pulse h-64 bg-gray-100 rounded-lg"></div> } protected function getOptions(): array { if (! $this->readyToLoad) { return []; } return ['chart' => ['type' => 'bar', 'height' => 300], 'series' => []]; } } ``` --- ## Live Polling — `CanPoll` Trait (via Filament) Chart data refreshes automatically on a configurable interval. Set `$pollingInterval` to a duration string or `null` to disable. ```php class LiveSalesChart extends ApexChartWidget { protected static ?string $chartId = 'liveSalesChart'; // Default is '5s'. Override with any valid interval string: protected static ?string $pollingInterval = '30s'; // Disable polling entirely: // protected static ?string $pollingInterval = null; protected function getOptions(): array { return [ 'chart' => ['type' => 'line', 'height' => 300], 'series' => [ ['name' => 'Orders', 'data' => \App\Models\Order::query() ->selectRaw('COUNT(*) as c') ->groupByRaw('HOUR(created_at)') ->pluck('c')->toArray()], ], ]; } } ``` --- ## Single-Select Filter — `CanFilter` Trait (`getFilters()` / `$filter`) Renders a `<select>` dropdown in the widget header. The selected value is available as `$this->filter` inside `getOptions()`. ```php class FilteredRevenueChart extends ApexChartWidget { protected static ?string $chartId = 'filteredRevenueChart'; protected static ?string $heading = 'Revenue'; // Default selected value public ?string $filter = 'month'; protected function getFilters(): ?array { return [ 'today' => 'Today', 'week' => 'Last week', 'month' => 'Last month', 'year' => 'This year', ]; } protected function getOptions(): array { $query = \App\Models\Order::query(); $data = match ($this->filter) { 'today' => $query->whereDate('created_at', today()), 'week' => $query->whereBetween('created_at', [now()->startOfWeek(), now()->endOfWeek()]), 'month' => $query->whereMonth('created_at', now()->month), 'year' => $query->whereYear('created_at', now()->year), default => $query, }; return [ 'chart' => ['type' => 'bar', 'height' => 300], 'series' => [['name' => 'Revenue', 'data' => $data->pluck('total')->toArray()]], ]; } } ``` --- ## Schema Filter Form — `HasFiltersSchema` Trait (`filtersSchema()`) Renders a dropdown panel with a full Filament schema form (date pickers, text inputs, selects, etc.). Filter state is available as `$this->filters['key']` inside `getOptions()`. ```php use Filament\Forms\Components\DatePicker; use Filament\Forms\Components\Select; use Filament\Schemas\Schema; use Filament\Widgets\ChartWidget\Concerns\HasFiltersSchema; use Leandrocfe\FilamentApexCharts\Widgets\ApexChartWidget; class AdvancedFilterChart extends ApexChartWidget { use HasFiltersSchema; protected static ?string $chartId = 'advancedFilterChart'; protected static ?string $heading = 'Sales by Category'; public function filtersSchema(Schema $schema): Schema { return $schema->components([ Select::make('category') ->options(\App\Models\Category::pluck('name', 'id')) ->default(1), DatePicker::make('date_start') ->default(now()->startOfMonth()->toDateString()), DatePicker::make('date_end') ->default(now()->endOfMonth()->toDateString()), ]); } // Called whenever a filter field value changes public function updatedInteractsWithSchemas(string $statePath): void { $this->updateOptions(); } protected function getOptions(): array { $categoryId = $this->filters['category'] ?? 1; $start = $this->filters['date_start'] ?? now()->startOfMonth(); $end = $this->filters['date_end'] ?? now()->endOfMonth(); $data = \App\Models\Sale::query() ->where('category_id', $categoryId) ->whereBetween('created_at', [$start, $end]) ->selectRaw('DATE(created_at) as date, SUM(amount) as total') ->groupBy('date') ->pluck('total', 'date'); return [ 'chart' => ['type' => 'area', 'height' => 300], 'series' => [['name' => 'Sales', 'data' => $data->values()->toArray()]], 'xaxis' => ['categories' => $data->keys()->toArray()], ]; } } ``` --- ## Mixed Chart (Multiple Series Types) Combine different chart types (e.g., bar columns + line) in a single widget by assigning a `type` per series. ```php class LineColumnChart extends ApexChartWidget { protected static ?string $chartId = 'lineColumnChart'; protected static ?string $heading = 'Revenue vs Target'; protected function getOptions(): array { return [ 'chart' => ['type' => 'line', 'height' => 300], 'series' => [ ['name' => 'Actual', 'data' => [20,40,60,100,140,70,20,90,100,150,130,180], 'type' => 'column'], ['name' => 'Target', 'data' => [10,20,30,50,40,70,30,10,60,80,20,18], 'type' => 'line'], ], 'stroke' => ['width' => [0, 4]], 'xaxis' => [ 'categories' => ['Jan','Feb','Mar','Apr','May','Jun', 'Jul','Aug','Sep','Oct','Nov','Dec'], ], 'legend' => ['labels' => ['colors' => '#9ca3af']], ]; } } ``` --- ## Annotations Add horizontal/vertical threshold lines and labels directly onto the chart via the `annotations` key. ```php class ColumnChartWithAnnotations extends ApexChartWidget { protected static ?string $chartId = 'annotatedChart'; protected static ?string $heading = 'Monthly Posts'; protected function getOptions(): array { return [ 'chart' => ['type' => 'bar', 'height' => 300], 'series' => [['name' => 'Posts', 'data' => [7,4,6,10,14,7,5,9,10,15,13,18]]], 'xaxis' => ['categories' => ['Jan','Feb','Mar','Apr','May','Jun', 'Jul','Aug','Sep','Oct','Nov','Dec']], 'colors' => ['#6366f1'], 'annotations' => [ 'yaxis' => [[ 'y' => 15, 'borderColor' => '#fcd34d', 'borderWidth' => '5', 'label' => [ 'borderColor' => '#f59e0b', 'style' => ['color' => '#fffbeb', 'background' => '#f59e0b'], 'text' => 'Target', ], ]], ], ]; } } ``` --- ## Radial Bar / Gradient Circle Chart A single-value radial bar chart with gradient fill and drop shadows, ideal for KPI gauges. ```php class GradientCircleChart extends ApexChartWidget { protected static ?string $chartId = 'kpiGauge'; protected static ?string $heading = 'Task Completion'; protected function getOptions(): array { $percent = \App\Models\Task::completedPercentage(); // e.g. 75 return [ 'chart' => ['type' => 'radialBar', 'height' => 300], 'series' => [$percent], 'labels' => ['Completion'], 'plotOptions' => [ 'radialBar' => [ 'startAngle' => -135, 'endAngle' => 225, 'hollow' => ['size' => '70%'], 'dataLabels' => [ 'name' => ['show' => true, 'offsetY' => -10, 'color' => '#9ca3af'], 'value' => ['show' => true, 'color' => '#9ca3af'], ], ], ], 'fill' => [ 'type' => 'gradient', 'gradient' => [ 'shade' => 'dark', 'type' => 'horizontal', 'gradientToColors' => ['#f43f5e'], 'stops' => [0, 100], ], ], 'stroke' => ['lineCap' => 'round'], 'colors' => ['#6366f1'], ]; } } ``` --- ## Publishing Views & Translations Publish Blade views to customise the widget template, or translations to localise filter labels. ```bash # Publish Blade views to resources/views/vendor/filament-apex-charts/ php artisan vendor:publish --tag="filament-apex-charts-views" # Publish translations to lang/vendor/filament-apex-charts/ php artisan vendor:publish --tag="filament-apex-charts-translations" ``` --- ## Registering Widgets in Filament Panels or Resources ```php // Dashboard widget — app/Providers/Filament/AdminPanelProvider.php use App\Filament\Widgets\BlogPostsChart; public function panel(Panel $panel): Panel { return $panel ->widgets([BlogPostsChart::class]); } // Resource widget — app/Filament/Resources/PostResource.php public static function getWidgets(): array { return [BlogPostsChart::class]; } public static function getHeaderWidgets(): array { return [BlogPostsChart::class]; } ``` --- Filament Apex Charts is primarily used to build rich, interactive admin dashboards that visualise application data through live-updating widgets. Common use cases include time-series metrics (revenue, signups, page views), KPI gauges (radial bar/donut with a single value), distribution charts (pie/polar area for category breakdowns), and multi-dimensional comparison charts (scatter, heatmap, mixed line-column). Because each widget is a Livewire component, all data retrieval is server-side, and polling or filter interactions happen without JavaScript outside the Alpine.js bridge layer. Integration patterns range from simple stand-alone dashboard widgets registered on a panel, to per-resource header/footer widgets that contextualise data alongside Filament tables. The `getOptions()` → `updateOptions()` cycle means any Livewire action, event listener, or form interaction can push fresh data to the chart, enabling real-time dashboards driven by Laravel Echo, polling, or manual user-triggered refreshes. The `extraJsOptions()` escape hatch allows raw JavaScript closures for custom formatter callbacks, keeping the PHP API clean while still accessing the full ApexCharts JavaScript API.