spatie/filament-simple-stats
Opinionated, prebuilt stat widgets for Filament dashboards. Quickly add daily counts and sums using Flowframe/laravel-trend, with helpers like last 30 days to generate clean, consistent stats cards with minimal setup.
Installation:
composer require spatie/filament-simple-stats
Ensure your project uses Filament v2+ and Laravel 10+ (or newer, as per changelog).
First Widget:
Create a Filament widget (e.g., app/Filament/Widgets/StatsOverview.php):
use Spatie\FilamentSimpleStats\SimpleStat;
use Filament\Widgets\Widget;
class StatsOverview extends Widget
{
protected function getStats(): array
{
return [
SimpleStat::make('Users')->model(\App\Models\User::class)->count(),
SimpleStat::make('Revenue')->model(\App\Models\Order::class)->sum('amount'),
];
}
}
Register the Widget:
Add it to your Filament dashboard in app/Providers/Filament/AdminPanelProvider.php:
public function panel(Panel $panel): Panel
{
return $panel
->widgets([
\App\Filament\Widgets\StatsOverview::class,
]);
}
Use SimpleStat to display real-time counts/sums with minimal code:
SimpleStat::make('Active Users')
->model(\App\Models\User::class)
->where('active', true)
->count()
->description('Last 7 days')
->last7Days();
Model-Based Stats:
SimpleStat::make('Orders')
->model(\App\Models\Order::class)
->last30Days()
->dailySum('total'); // Sums 'total' column daily
Query Customization:
SimpleStat::make('High-Value Users')
->model(\App\Models\User::class)
->where('lifetime_value', '>', 1000)
->count();
Trend Analysis:
SimpleStat::make('Monthly Revenue')
->model(\App\Models\Order::class)
->last12Months()
->monthlySum('amount')
->description('YoY Growth');
Dynamic Data: Use closures for runtime conditions (e.g., user-specific stats):
SimpleStat::make('My Orders')
->model(\App\Models\Order::class)
->where(fn ($query) => $query->where('user_id', auth()->id()))
->count();
Custom Aggregations: Extend with raw SQL or custom Eloquent queries:
SimpleStat::make('Avg. Order Value')
->query(\App\Models\Order::query()->avg('amount'))
->withoutTrend();
Conditional Rendering: Hide stats based on permissions or data availability:
protected function getStats(): array
{
return auth()->user()->can('view_analytics')
? [SimpleStat::make('Analytics')->model(...)]
: [];
}
Nested Stats:
Combine with Filament’s Stat for custom formatting:
use Filament\Widgets\StatsOverviewWidget\Stat;
Stat::make('Users', User::count())
->description('Total')
->chart([...]);
Time-Based Segmentation:
Use lastNDays(), lastNMonths(), or between() for granular trends:
SimpleStat::make('Q1 Revenue')
->model(\App\Models\Order::class)
->between('2024-01-01', '2024-03-31')
->sum('amount');
Multi-Model Aggregations: Join tables for cross-model stats:
SimpleStat::make('User Orders')
->query(\App\Models\Order::query()
->selectRaw('user_id, count(*) as orders')
->groupBy('user_id'))
->sum('orders');
Performance:
last30Days()->dailySum()) on large tables may slow dashboards.cache() or use database indexes:
SimpleStat::make('Users')->cache(fn () => User::count(), now()->addHours(1));
Trend Accuracy:
withoutTrend() disables all trend calculations, which may mislead users.invertTrendColors() for metrics where decreases are positive (e.g., errors).Time Zone Mismatches:
lastNDays() uses the server’s timezone. Client-side dashboards may show stale data.SimpleStat::make('Users')->model(User::class)
->whereDate('created_at', '>=', now()->timezone('UTC')->subDays(7));
Query Inspection:
Use toSql() to debug queries:
$query = SimpleStat::make('Users')->model(User::class)->count()->getQuery();
dd($query->toSql(), $query->getBindings());
Trend Calculation:
Verify trend logic by inspecting the underlying Trend model:
$stat = SimpleStat::make('Users')->last7Days()->count();
dd($stat->getTrendData()); // Check raw trend values
Custom Stat Classes:
Extend SimpleStat for reusable logic:
class UserStat extends SimpleStat
{
public function activeCount(): self
{
return $this->where('active', true)->count();
}
}
Override Defaults: Modify trend colors or icons via Filament’s theme:
// config/filament.php
'colors' => [
'success' => '#10b981', // Custom green for trends
];
Localization: Translate stat labels dynamically:
SimpleStat::make(__('Users'))->model(User::class)->count();
A/B Testing:
Use withoutTrend() for control groups to test impact of trend visuals.
Dark Mode: Ensure trend icons/colors are visible in dark mode by overriding Filament’s CSS:
.filament-widgets-stat-trend--down {
color: #ef4444; /* Red for dark mode */
}
Accessibility:
Add aria-label for screen readers:
SimpleStat::make('Users')->model(User::class)
->count()
->description('Total active users')
->extraAttributes(['aria-label' => 'Active user count']);
How can I help you explore Laravel packages today?