harvirsidhu/filament-cards
| Install | |
|---|---|
composer require harvirsidhu/filament-cards |
|
| Latest Version: | v1.0.6 |
| PHP: | ^8.2 |
| License: | MIT |
| Last Updated: | Feb 19, 2026 |
| Links: | GitHub · Packagist |
Filament Cards
A Filament-native plugin that turns your pages and resources into a card-based navigation hub. Built to feel like it belongs in Filament's core -- uses the same API patterns (label, schema, columnSpan, visible/hidden) and integrates natively with Clusters and Resources.
Best used as a Cluster or Resource front page that auto-discovers child pages and resources, respecting Filament's existing navigation configuration. Also works standalone as a general-purpose settings hub.
Screenshot

Documentation
Index
- Requirements
- Installation
- Quick Start (Manual Cards)
- Use Case: Cluster Front Page (Primary)
- Use Case: Resource Hub
- Use Case: Standalone Page
- API Reference: CardItem
- API Reference: CardGroup
- API Reference: CardsPage Configuration
- Advanced: Dynamic Registration
- Full Example (Putting It All Together)
- Optional: Filament Plugin Registration
- License
Feature Overview
- Auto-discovery for Cluster and Resource pages with built-in authorization checks.
- Filament-native API (
label,description,schema,visible,hidden, etc.). - Grouping and layout controls via
CardGroup, columns, spans, compact mode, and collapse behavior. - Flexible visibility using component-level methods/properties or page-level include/exclude hooks.
- Manual + discovered cards together so you can combine internal routes and external links.
- Dynamic registration for modular apps and package-driven extension points.
Requirements
- PHP 8.2+
- Laravel 11+
- Filament v4 or v5
Installation
Install via Composer:
composer require harvirsidhu/filament-cards
Theme Setup
Since the plugin uses Tailwind CSS classes, add the plugin's views to your theme.
For Filament v4.x / v5.x, add this line to your theme.css:
@source '../../../../vendor/harvirsidhu/filament-cards/resources/views';
Then rebuild your assets:
npm run build
Quick Start (Manual Cards)
The simplest possible cards page in 10 lines:
namespace App\Filament\Pages;
use Harvirsidhu\FilamentCards\Filament\Pages\CardsPage;
use Harvirsidhu\FilamentCards\CardItem;
class ControlPanel extends CardsPage
{
protected static ?string $navigationIcon = 'heroicon-o-squares-2x2';
protected static function getCards(): array
{
return [
CardItem::make(CompanySettings::class),
CardItem::make(BillingSettings::class),
];
}
}
Use Case: Cluster Front Page (Primary)
The most powerful way to use this plugin is as the front page of a Cluster. Auto-discovery reads all pages and resources in the cluster and creates cards automatically.
Step 1: Define the Cluster
namespace App\Filament\Clusters;
use Filament\Clusters\Cluster;
class Settings extends Cluster
{
protected static ?string $navigationIcon = 'heroicon-o-cog-8-tooth';
}
Step 2: Create the CardsPage
namespace App\Filament\Clusters\Settings\Pages;
use App\Filament\Clusters\Settings;
use Harvirsidhu\FilamentCards\Filament\Pages\CardsPage;
class SettingsHub extends CardsPage
{
protected static ?string $cluster = Settings::class;
protected static ?int $navigationSort = -1;
protected static function getCards(): array
{
return static::discoverClusterCards();
}
}
Step 3: Your Cluster Pages Work as Normal
No extra traits or changes needed on any of your pages.
To add a description to the card, simply add a $navigationDescription property to your page class:
namespace App\Filament\Clusters\Settings\Pages;
use Filament\Pages\Page;
use App\Filament\Clusters\Settings;
class CompanySettings extends Page
{
protected static ?string $cluster = Settings::class;
protected static ?string $navigationIcon = 'heroicon-o-building-office';
// Optional: Add a description to the card
public static ?string $navigationDescription = 'Manage company name, address, and branding.';
}
Breadcrumbs work automatically: Dashboard > Settings > Company Settings. Filament's cluster breadcrumb system handles everything -- no custom traits needed.
discoverClusterCards()
- Reads all pages and resources registered to the Cluster
- Excludes the CardsPage itself
- Checks
canAccess()on each component (respects authorization) - Checks cards visibility via
showInFilamentCards()or$showInFilamentCards(if defined on the component), otherwise falls back toshouldRegisterNavigation() - Uses each page's
$navigationLabel,$navigationIcon, and URL - Reads
getNavigationBadge()/getNavigationBadgeColor()when available - New: Checks for
$navigationDescriptionproperty (orgetNavigationDescription()method) on the page class - Groups cards by
getFilamentCardsGroup()/$filamentCardsGroup(if defined), otherwise falls back to$navigationGroup - Sorts by
$navigationSort
Hiding Auto-Discovered Cards
You can hide a Page/Resource from auto-discovery in two ways.
1) On the Page/Resource itself (recommended)
class InternalToolsPage extends Page
{
public static function showInFilamentCards(): bool
{
return false;
}
}
Or with a static property:
class AuditLogsResource extends Resource
{
public static bool $showInFilamentCards = false;
}
To force-show a component in cards even if shouldRegisterNavigation() is false:
class HiddenFromSidebarPage extends Page
{
public static function shouldRegisterNavigation(): bool
{
return false;
}
public static function showInFilamentCards(): bool
{
return true;
}
}
2) On the CardsPage (central control)
class SettingsHub extends CardsPage
{
protected static array $excludedClusterComponents = [
AuditLogsResource::class,
InternalToolsPage::class,
];
}
Grouping Auto-Discovered Cards
By default, discovered cards use each component's navigation group (getNavigationGroup() / $navigationGroup).
If you want a different group just for cards, define it on the Page/Resource:
class CompanySettings extends Page
{
public static function getFilamentCardsGroup(): ?string
{
return 'Business Settings';
}
}
Or with a static property:
class BillingResource extends Resource
{
public static ?string $filamentCardsGroup = 'Finance';
}
Mixing Auto-Discovered and Manual Cards
protected static function getCards(): array
{
return [
...static::discoverClusterCards(),
CardGroup::make('External Links')
->schema([
CardItem::make('https://docs.example.com')
->label('Documentation')
->icon('heroicon-o-book-open')
->openUrlInNewTab(),
]),
];
}
Use Case: Resource Hub
When a Resource has many custom pages, use discoverResourceCards() to auto-create cards for each:
namespace App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource;
use Harvirsidhu\FilamentCards\Filament\Pages\CardsPage;
class UserSettingsHub extends CardsPage
{
protected static string $resource = UserResource::class;
protected static function getCards(): array
{
return static::discoverResourceCards();
}
}
Use Case: Standalone Page
Without a Cluster or Resource, define cards manually:
use Harvirsidhu\FilamentCards\CardItem;
use Harvirsidhu\FilamentCards\CardGroup;
use Harvirsidhu\FilamentCards\Filament\Pages\CardsPage;
class ControlPanel extends CardsPage
{
protected static ?string $navigationIcon = 'heroicon-o-squares-2x2';
protected static function getCards(): array
{
return [
CardGroup::make('General')
->icon('heroicon-o-cog')
->description('Core settings')
->schema([
CardItem::make(CompanySettings::class)->color('primary'),
CardItem::make(BillingSettings::class)->color('success'),
]),
CardItem::make('/external/docs')
->label('Documentation')
->icon('heroicon-o-document-text')
->openUrlInNewTab(),
];
}
}
API Reference: CardItem
Creating a Card Item
Pass a Filament Page class, Resource class, or a URL string:
CardItem::make(CompanySettings::class) // Filament Page
CardItem::make(UserResource::class) // Filament Resource
CardItem::make('/custom/path') // URL string
CardItem::make('https://example.com') // External URL
When a Page or Resource class is passed, the card automatically resolves its label, icon, badge, badgeColor, and url from the class's navigation properties.
label()
Override the card title. Accepts a string or Closure:
CardItem::make(CompanySettings::class)
->label('Company')
CardItem::make(CompanySettings::class)
->label(fn () => __('settings.company'))
description()
Add a subtitle below the card title:
CardItem::make(CompanySettings::class)
->description('Manage company name, address, and branding')
Auto-Discovery: If you are using discoverClusterCards() or discoverResourceCards(), you can add a static property to your page class instead:
class CompanySettings extends Page
{
public static ?string $navigationDescription = 'Manage company details.';
}
badge()
Add a badge to the right side of the card title:
CardItem::make(CompanySettings::class)
->badge('Beta')
badgeColor()
Set the badge color using Filament color names (or an equivalent color definition):
CardItem::make(CompanySettings::class)
->badge('12')
->badgeColor('primary')
Auto-Discovery: If you are using discoverClusterCards() or discoverResourceCards(), badge values are read from getNavigationBadge() and getNavigationBadgeColor() when available on the discovered Page/Resource.
icon()
Override the card icon:
CardItem::make('/path')
->icon('heroicon-o-building-office')
url() and openUrlInNewTab()
Override the URL or open in a new tab:
CardItem::make(CompanySettings::class)
->url('https://custom-url.com')
->openUrlInNewTab()
alignment()
Control the text alignment of the card content. Options: Start, Center, End, Justify:
use Filament\Support\Enums\Alignment;
CardItem::make(CompanySettings::class)
->alignment(Alignment::Center)
visible() and hidden()
Control card visibility. Accepts a boolean or Closure:
CardItem::make(BillingSettings::class)
->visible(fn () => auth()->user()->can('manage-billing'))
CardItem::make(DangerZone::class)
->hidden(fn () => ! auth()->user()->isAdmin())
color()
Add a color accent to the card. Supports Filament's color system:
CardItem::make(CompanySettings::class)->color('primary')
CardItem::make(BillingSettings::class)->color('success')
CardItem::make(DangerZone::class)->color('danger')
CardItem::make(Notifications::class)->color('warning')
CardItem::make(ApiSettings::class)->color('info')
CardItem::make(LegacySettings::class)->color('gray')
Available colors: primary, success, danger, warning, info, gray.
disabled()
Show the card but make it non-clickable with reduced opacity:
CardItem::make(DangerZone::class)
->disabled(fn () => ! auth()->user()->isAdmin())
sort()
Control the order of cards within a group:
CardItem::make(CompanySettings::class)->sort(1)
CardItem::make(BillingSettings::class)->sort(2)
CardItem::make(NotificationPrefs::class)->sort(3)
columnSpan() and columnSpanFull()
Control how many grid columns a card occupies:
// Span 2 columns
CardItem::make(CompanySettings::class)->columnSpan(2)
// Span the full width
CardItem::make(NotificationPrefs::class)->columnSpanFull()
// Responsive spans
CardItem::make(CompanySettings::class)->columnSpan([
'default' => 1,
'md' => 2,
'lg' => 3,
])
extraAttributes()
Add custom HTML attributes to the card element:
CardItem::make(CompanySettings::class)
->extraAttributes([
'data-analytics' => 'company-settings',
'id' => 'company-card',
])
API Reference: CardGroup
Groups organize cards under a collapsible header, similar to Filament's Section.
Creating a Group
use Harvirsidhu\FilamentCards\CardGroup;
CardGroup::make('General Settings')
->schema([
CardItem::make(CompanySettings::class),
CardItem::make(BillingSettings::class),
])
schema()
Define the card items in the group:
CardGroup::make('General')
->schema([
CardItem::make(CompanySettings::class),
CardItem::make(BillingSettings::class),
])
columns()
Override the grid columns for this specific group. You can use a single integer, or a responsive array (same style as Filament widgets):
CardGroup::make('Wide Cards')
->columns(2)
->schema([...])
CardGroup::make('Wide Cards')
->columns([
'md' => 2,
'xl' => 4,
])
->schema([...])
collapsible() and collapsed()
Make the group collapsible, optionally starting collapsed:
CardGroup::make('Advanced')
->collapsible()
->schema([...])
CardGroup::make('Advanced')
->collapsed() // Starts collapsed, implicitly collapsible
->schema([...])
CardGroup::make('Advanced')
->collapsed(fn () => ! auth()->user()->isAdmin())
->schema([...])
compact()
Reduce padding and gaps for a denser layout:
CardGroup::make('Quick Links')
->compact()
->schema([...])
label(), description(), icon()
Customize the group header:
CardGroup::make('General')
->label('General Settings')
->description('Core application configuration')
->icon('heroicon-o-cog')
->schema([...])
Group-level visible() and hidden()
Hide an entire group conditionally:
CardGroup::make('Admin Only')
->hidden(fn () => ! auth()->user()->isAdmin())
->schema([...])
API Reference: CardsPage Configuration
Customize the CardsPage with static properties:
$columns
Default number of grid columns (default: 3).
Supports Filament widget-style responsive values:
class ControlPanel extends CardsPage
{
protected static string|int|array $columns = 4;
}
class ControlPanel extends CardsPage
{
protected static string|int|array $columns = [
'md' => 2,
'xl' => 4,
];
}
$itemsAlignment
Alignment of card content. Options: Start, Center, End, Justify (default: Center):
use Filament\Support\Enums\Alignment;
class ControlPanel extends CardsPage
{
protected static Alignment $itemsAlignment = Alignment::Center;
}
$iconSize
Size of card icons. Options: Small, Medium, Large (default: Medium):
use Filament\Support\Enums\IconSize;
class ControlPanel extends CardsPage
{
protected static IconSize $iconSize = IconSize::Small;
}
$iconInlined
Display the icon inline with the title instead of stacked above it:
class ControlPanel extends CardsPage
{
protected static bool $iconInlined = true;
}
$iconPosition
Controls whether the icon appears before or after the label. Options: Before, After (default: Before):
use Filament\Support\Enums\IconPosition;
class ControlPanel extends CardsPage
{
protected static IconPosition $iconPosition = IconPosition::After;
}
$excludedClusterComponents
Exclude specific Cluster pages/resources from discoverClusterCards():
class SettingsHub extends CardsPage
{
protected static array $excludedClusterComponents = [
AuditLogsResource::class,
InternalToolsPage::class,
];
}
$excludedResourcePages
Exclude specific Resource pages from discoverResourceCards():
class UserSettingsHub extends CardsPage
{
protected static array $excludedResourcePages = [
UserResource\Pages\DangerZone::class,
];
}
shouldIncludeDiscoveredCard()
Override this hook for advanced, centralized filtering:
protected static function shouldIncludeDiscoveredCard(string $component): bool
{
if (! parent::shouldIncludeDiscoveredCard($component)) {
return false;
}
return $component !== BetaFeaturePage::class;
}
Advanced: Dynamic Registration
Add cards to a CardsPage from outside the class -- useful for modular applications or packages:
use App\Filament\Pages\ControlPanel;
use Harvirsidhu\FilamentCards\CardItem;
// In a service provider boot() method:
ControlPanel::addCards([
CardItem::make(UserManagement::class)
->label('User Accounts')
->icon('heroicon-o-users')
->description('Manage roles, permissions, and user accounts'),
]);
Full Example (Putting It All Together)
use Harvirsidhu\FilamentCards\CardItem;
use Harvirsidhu\FilamentCards\CardGroup;
use Harvirsidhu\FilamentCards\Filament\Pages\CardsPage;
use Filament\Support\Enums\Alignment;
use Filament\Support\Enums\IconPosition;
use Filament\Support\Enums\IconSize;
class SettingsHub extends CardsPage
{
protected static ?string $navigationIcon = 'heroicon-o-cog-8-tooth';
protected static int $columns = 3;
protected static Alignment $itemsAlignment = Alignment::Center;
protected static IconSize $iconSize = IconSize::Medium;
protected static IconPosition $iconPosition = IconPosition::Before;
protected static function getCards(): array
{
return [
CardGroup::make('General')
->icon('heroicon-o-cog')
->description('Core application settings')
->collapsible()
->schema([
CardItem::make(CompanySettings::class)
->color('primary'),
CardItem::make(BillingSettings::class)
->visible(fn () => auth()->user()->can('manage-billing'))
->color('success')
->sort(2),
CardItem::make(NotificationPrefs::class)
->description('Email, SMS & push notification preferences')
->columnSpanFull(),
]),
CardGroup::make('Danger Zone')
->icon('heroicon-o-exclamation-triangle')
->collapsed()
->columns(2)
->schema([
CardItem::make(DangerZone::class)
->color('danger')
->disabled(fn () => ! auth()->user()->isAdmin()),
]),
CardItem::make('https://docs.example.com')
->label('Documentation')
->icon('heroicon-o-book-open')
->openUrlInNewTab()
->extraAttributes(['data-track' => 'docs']),
];
}
}
Optional: Filament Plugin Registration
Optionally register the plugin in your panel provider:
use Harvirsidhu\FilamentCards\FilamentCardsPlugin;
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
FilamentCardsPlugin::make(),
]);
}
License
The MIT License (MIT). Please see License File for more information.