Dashboard widgets · Open source
Stat Cards
Adds progress bars, icon tiles, card and text colours, trends, badges and bar charts to the stats overview widget you already have, by changing one import.
What it solves
Filament's stat card shows a label, a value, a description and a line sparkline.
A target, a percentage change against last month or a coloured card means writing your own widget view.
This package's Stat is a subclass of Filament's stats overview Stat, so it goes in the same getStats() array and core's methods still work. It adds a progress bar with an optional label, the icon in a coloured tile at the start or end of the card, colours for the card, icon, label, value and description, trend(current, previous) that writes "12.4% increase" with an arrow in green or red, a badge next to the label and a bar chart drawn as plain SVG. The styles are plain CSS, so there is no theme or build step. It also accepts the stat method names of eightynine/filament-advanced-widgets. An independent plugin, not made or endorsed by Filament.
- A subclass of Filament's stats overview Stat: swap one use line, keep your widget, and mix core and enhanced stats in the same widget
- Progress bars filled to value / max, clamped to 0-100%, with the percentage or your own text underneath
- Icon tiles: the icon in a coloured square, before the label or at the far end of the card
- Colours for the card background, the icon, the label, the value and the description, from any Filament colour name or palette array
- trend($current, $previous) writes "12.4% increase" or "22.5% decrease" with an arrow, green when the change is good and red when it is bad, with higherIsBetter: false for refunds or churn
- A badge after the label, such as "This month" or "Live"
- chartType('bar') draws the chart data as columns in plain SVG, with no JavaScript
- Plain CSS, linked when published by filament:assets and printed inline otherwise; no theme, Tailwind config or npm build
- Dark mode uses solid colours on neutral surfaces, never a translucent colour wash
Install
Requires PHP 8.2+, Filament 4 and 5, and Laravel 12 and 13.
composer require amjadiqbal/filament-stat-cards
Usage
use AmjadIqbal\FilamentStatCards\Stat;
protected function getStats(): array
{
return [
Stat::make('Revenue', '$48,200')
->icon('heroicon-o-banknotes')
->iconBackgroundColor('primary')
->trend(48200, 42880)
->progress(48200, 60000)
->progressLabel('80% of the $60k target')
->badge('This month', 'primary'),
];
}
Setup
There is no plugin to register on the panel, no new widget class and no theme or npm build: the service provider is discovered automatically and the styles are plain CSS. If you run php artisan filament:assets, the panel links the published stylesheet; if not, the same CSS (about 5 KB) is printed inline in the panel's head. Core Stat objects and these ones can sit in the same widget.
- 1 composer require amjadiqbal/filament-stat-cards
- 2 In a stats overview widget, replace use Filament\Widgets\StatsOverviewWidget\Stat; with use AmjadIqbal\FilamentStatCards\Stat;
- 3 Optional: php artisan vendor:publish --tag=filament-stat-cards-translations to change the trend and progress texts.
Progress bars
progress($value, $max = 100) shows a bar under the description, filled to $value / $max and clamped to 0-100%. The bar uses progressBarColor() (or its alias progressColor()), else the stat's color(), else primary. progressLabel(true) prints the percentage under the bar, rounded to a whole number; a string prints that text instead.
Stat::make('Storage used', '612 GB')
->progress(612, 1024)
->progressBarColor('info')
->progressLabel('612 of 1,024 GB');
Icon tiles
iconBackgroundColor() puts the stat's icon in a coloured square. The icon takes the tile's colour unless iconColor() sets another; iconColor() on its own colours a plain icon. iconPosition('start'), the default, puts the icon before the label as core does; iconPosition('end') puts it at the far end of the top row. before and after, and Filament's IconPosition enum, also work; any other value throws an exception.
Stat::make('Revenue', '$48,200')
->icon('heroicon-o-banknotes')
->iconBackgroundColor('primary')
->iconPosition('end');
Colours
backgroundColor() tints the card. labelColor() and valueColor() colour the text, and textColor($label, $value, $description) sets all three at once, skipping any you pass as null. The label and value colours also take a closure; the description colour is core's, a name or a palette array. Core's descriptionColor() and chartColor() work as before.
- A colour is any Filament colour name (primary, success, warning, danger, info, gray, or one you registered) or a palette array such as Color::Sky or Color::hex('#0ea5e9').
- Named colours point at the panel's own colour variables, so the cards follow your theme.
Stat::make('New signups', '1,204')
->backgroundColor('info')
->valueColor('info')
->description('Since Monday');
Trends
trend($current, $previous, $higherIsBetter = true, $precision = 1) writes the description, the arrow and the colour from two numbers. The change is (current - previous) / previous, as a percentage of the previous value's size, rounded to $precision decimals, with trailing zeros dropped: 48200 against 42880 gives "12.4% increase", and an exact 12.0 shows as "12%". A rise gets an up arrow and a fall a down arrow. The text is green when the change is good and red when it is bad; higherIsBetter: false flips that for numbers that should go down.
- Previous is 0: no percentage can be worked out, so the description is "New this period" (or "No change" if current is 0 too), with no arrow, in the stat's color() if it has one.
- A change that rounds to zero reads "No change", with no arrow.
- Your own description(), descriptionIcon() or descriptionColor() wins over the one trend() would write.
- The texts come from the package's translation file, which you can publish.
Stat::make('Refunds', '31')
->trend(31, 40, higherIsBetter: false); // "22.5% decrease", green
Badges
badge($text, $color = null) shows a small badge after the label, such as "Live", "Beta" or "This month". Without a colour it uses the stat's color(), else gray.
Stat::make('Pending orders', '86')
->badge('Needs attention', 'warning');
Bar charts
chartType('bar') draws the chart() data as columns instead of core's line sparkline. The bars are plain SVG with no JavaScript, scaled to the largest value, and use chartColor(), else the stat's color(), else gray. chartType('line'), the default, leaves core's sparkline as it is. Any other type throws an exception.
Stat::make('Refunds', '31')
->chart([4, 9, 6, 12, 8, 14])
->chartType('bar')
->chartColor('danger');
Coming from eightynine/filament-advanced-widgets
eightynine/filament-advanced-widgets (MIT, by Eighty Nine) popularised these cards for Filament 3 and 4. Stat Cards is a separate, independent implementation for Filament 4 and 5 with no shared code. It accepts the same stat method names: backgroundColor, progress, progressBarColor, iconBackgroundColor, iconColor, iconPosition, labelColor, valueColor, textColor, descriptionIcon, descriptionColor and chartColor. It is not affiliated with or endorsed by its author.
- 1 Replace use EightyNine\FilamentAdvancedWidget\AdvancedStatsOverviewWidget\Stat; with use AmjadIqbal\FilamentStatCards\Stat;
- 2 Replace use EightyNine\FilamentAdvancedWidget\AdvancedStatsOverviewWidget as BaseWidget; with use Filament\Widgets\StatsOverviewWidget as BaseWidget;
- 3 Check the result in the browser: the cards look different.
- The icon defaults to the start of the card, as in core. Add iconPosition('end') where you want it at the end.
- progress() takes a number (out of 100 unless you pass a maximum), not a word: replace 'full' with 100 and 'empty' with 0.
- chartColor() takes one colour, as in core; a second argument is ignored, and borderColor() and graphColor() do not exist here.
- Only the stats widget is covered, not eightynine's chart or table widgets.
Dark mode
In dark mode, colours appear only as solid text, lines, bars and borders on Filament's neutral surfaces. The package never puts a translucent colour wash on a dark card, where warm colours turn muddy.
- A card with backgroundColor() keeps the neutral dark surface and gets a solid coloured line along its top.
- Icon tiles and badges become coloured outlines on a transparent background.
- Core's sparkline is drawn as a line without its area fill, in these cards only.
Hire me
Need this built into your app, or something custom?
I wrote Stat Cards. I can wire it into your Filament panel, extend it for your case, or build the feature around it. Tell me what you need and you'll get a plan and a quote, free.
Support
Found a bug or want a feature? Open an issue on GitHub. For help adding it to your own project, use the quote form above.
More Filament plugins
All plugins
RankForge Lite
Adds meta, Open Graph and X fields to any Filament resource, scores the content for SEO and readability as you type, and previews the Google result before you publish.
Change Requests
Holds edits to Filament records as change requests that a reviewer checks field by field, then approves, rejects or rolls back.
Deleted Records
Lists the records spatie/laravel-deleted-models kept when they were deleted, previews their stored attributes, and restores or permanently deletes them.
Uptime Monitor
Lists the sites spatie/laravel-uptime-monitor watches with their uptime and certificate status, and lets you add, edit, check, turn on and off and delete them from your panel.