| Install | |
|---|---|
composer require harvirsidhu/filament-cards |
|
| Latest Version: | v1.0.6 |
| PHP: | ^8.2 |
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.

label, description, schema, visible, hidden, etc.).CardGroup, columns, spans, compact mode, and collapse behavior.Install via Composer:
composer require harvirsidhu/filament-cards
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
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),
];
}
}
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.
namespace App\Filament\Clusters;
use Filament\Clusters\Cluster;
class Settings extends Cluster
{
protected static ?string $navigationIcon = 'heroicon-o-cog-8-tooth';
}
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();
}
}
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()canAccess() on each component (respects authorization)showInFilamentCards() or $showInFilamentCards (if defined on the component), otherwise falls back to shouldRegisterNavigation()$navigationLabel, $navigationIcon, and URLgetNavigationBadge() / getNavigationBadgeColor() when available$navigationDescription property (or getNavigationDescription() method) on the page classgetFilamentCardsGroup() / $filamentCardsGroup (if defined), otherwise falls back to $navigationGroup$navigationSortYou can hide a Page/Resource from auto-discovery in two ways.
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;
}
}
class SettingsHub extends CardsPage
{
protected static array $excludedClusterComponents = [
AuditLogsResource::class,
InternalToolsPage::class,
];
}
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';
}
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(),
]),
];
}
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();
}
}
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(),
];
}
}
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',
])
Groups organize cards under a collapsible header, similar to Filament's Section.
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([...])
visible() and hidden()Hide an entire group conditionally:
CardGroup::make('Admin Only')
->hidden(fn () => ! auth()->user()->isAdmin())
->schema([...])
Customize the CardsPage with static properties:
$columnsDefault 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,
];
}
$itemsAlignmentAlignment 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;
}
$iconSizeSize of card icons. Options: Small, Medium, Large (default: Medium):
use Filament\Support\Enums\IconSize;
class ControlPanel extends CardsPage
{
protected static IconSize $iconSize = IconSize::Small;
}
$iconInlinedDisplay the icon inline with the title instead of stacked above it:
class ControlPanel extends CardsPage
{
protected static bool $iconInlined = true;
}
$iconPositionControls 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;
}
$excludedClusterComponentsExclude specific Cluster pages/resources from discoverClusterCards():
class SettingsHub extends CardsPage
{
protected static array $excludedClusterComponents = [
AuditLogsResource::class,
InternalToolsPage::class,
];
}
$excludedResourcePagesExclude 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;
}
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'),
]);
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']),
];
}
}
Optionally register the plugin in your panel provider:
use Harvirsidhu\FilamentCards\FilamentCardsPlugin;
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
FilamentCardsPlugin::make(),
]);
}
The MIT License (MIT). Please see License File for more information.