wezlo/filament-responsive-table
Composer 安装命令:
composer require wezlo/filament-responsive-table
包简介
Render a Filament list table as stacked cards below a configurable Tailwind breakpoint.
README 文档
README
Render a Filament list table as stacked cards below a configurable Tailwind breakpoint. Above the breakpoint nothing changes — the native Filament table renders untouched. Below the breakpoint each row becomes a card with column labels, values, and the row's record actions in the footer.
The same table() definition drives both views — no duplicate column lists, no second source of truth.
Requirements
- PHP 8.2+
- Laravel 11+ / 13
- Filament 4 or 5
Features
- Breakpoint-driven — pick
sm,md,lg,xl, or2xl; below it the table becomes cards, above it the native table renders - Zero duplication — columns and record actions come straight from your existing
table()method - Two-column label/value grid inside each card, matching mobile UX expectations
- Optional per-card title resolved from the record
- Optional bulk-selection checkbox on each card so bulk actions still work on mobile
- Optional record actions footer — stack the row's actions at the bottom of each card
- Column filtering —
only()/except()hide columns in cards without affecting the desktop table - Custom card Blade view — opt out of the default template whenever you need it
- Plugin-level defaults — set a single default breakpoint for every responsive list page in a panel
- Three-level configuration cascade — page overrides plugin overrides config file
- Dark mode support
Installation
composer require wezlo/filament-responsive-table
Optionally register the plugin in your Panel Provider for global defaults:
use Wezlo\FilamentResponsiveTable\FilamentResponsiveTablePlugin; ->plugins([ FilamentResponsiveTablePlugin::make() ->defaultBreakpoint('md'), ])
Optionally publish the config:
php artisan vendor:publish --tag=filament-responsive-table-config
Theme Source (Tailwind v4)
The package's Blade views use Tailwind utility classes. For Tailwind to detect them during your app's build, add the package's views as a @source in your Filament custom theme CSS file (usually resources/css/filament/admin/theme.css):
@import '../../../../vendor/filament/filament/resources/css/theme.css'; @source '../../../../vendor/wezlo/filament-responsive-table/resources/views/**/*'; @custom-variant dark (&:where(.dark, .dark *));
If you don't have a custom theme yet, create one:
php artisan make:filament-theme
Then rebuild assets:
npm run build
Quick Start
Add the HasResponsiveTable trait to your resource's ListRecords page and declare a $responsiveBreakpoint property to pick the breakpoint:
use Filament\Resources\Pages\ListRecords; use Wezlo\FilamentResponsiveTable\Concerns\HasResponsiveTable; class ListUsers extends ListRecords { use HasResponsiveTable; protected static string $resource = UserResource::class; public ?string $responsiveBreakpoint = 'md'; }
That's it. At viewports < md (768px) every row collapses into a card showing each column's label on the left and its rendered value on the right. Record actions stack in a footer below.
The trait does not declare
$responsiveBreakpointitself (to avoid PHP trait/class property conflicts), so you declare it on your list page with whatever visibility and default you like —public,protected,?string, or a non-nullablestringwith a default value all work.
Configuration API
For anything beyond the breakpoint shortcut, implement the responsiveTable() method. The configuration from the method wins over the $responsiveBreakpoint property.
use Wezlo\FilamentResponsiveTable\Concerns\HasResponsiveTable; use Wezlo\FilamentResponsiveTable\ResponsiveTableConfiguration; class ListUsers extends ListRecords { use HasResponsiveTable; public function responsiveTable(ResponsiveTableConfiguration $config): ResponsiveTableConfiguration { return $config ->breakpoint('lg') ->except(['id', 'created_at']) ->cardTitle(fn ($record) => $record->name) ->showRecordActions() ->showBulkSelection(); } }
Configuration Reference
| Method | Signature | Description |
|---|---|---|
breakpoint(string) |
'sm' | 'md' | 'lg' | 'xl' | '2xl' |
Below this Tailwind breakpoint, rows render as cards. Throws on unknown values. |
only(array) |
array<string> |
Keep only these column names in cards. Desktop table is untouched. |
except(array) |
array<string> |
Hide these column names from cards. Desktop table is untouched. |
cardTitle(Closure) |
fn (Model $record): string|Htmlable|null |
Resolve a per-card header title from the record. |
showRecordActions(bool) |
bool (default true) |
Render the table's record actions in each card's footer. |
showBulkSelection(bool) |
bool (default false) |
Show the bulk-selection checkbox on each card. |
cardView(string) |
string |
Override the default card Blade template. |
Column Filtering
only() and except() match against Column::getName() — the first argument to TextColumn::make('name'), IconColumn::make('status'), etc. Nested relationship columns like client.name match by that exact name.
$config->only(['name', 'email', 'status']); // or $config->except(['id', 'created_at', 'updated_at', 'deleted_at']);
Card Title
Without cardTitle(), the card has no header bar — it's just label/value rows and the action footer. Setting it renders a header strip with the title text (and the bulk checkbox if enabled).
$config->cardTitle(fn ($record) => "#{$record->invoice_number}"); $config->cardTitle(fn ($record) => new HtmlString("<strong>{$record->name}</strong>"));
Custom Card View
Point to your own Blade view if the default layout doesn't fit:
$config->cardView('users.mobile-card');
The view receives three variables:
| Variable | Type | Description |
|---|---|---|
$record |
Model |
The Eloquent record for this card |
$columns |
array<Column> |
The visible card columns (after only/except) |
$config |
ResponsiveTableConfiguration |
The resolved configuration |
You can use $this->getResponsiveTableRecordActions($record) inside the view to get the cloned, record-bound, visibility-filtered actions array.
Plugin Configuration
Register the plugin in your Panel Provider to set defaults for all responsive list pages in that panel:
use Wezlo\FilamentResponsiveTable\FilamentResponsiveTablePlugin; public function panel(Panel $panel): Panel { return $panel ->plugins([ FilamentResponsiveTablePlugin::make() ->defaultBreakpoint('md') ->defaultShowRecordActions(true) ->defaultShowBulkSelection(false), ]); }
| Method | Type | Default | Description |
|---|---|---|---|
defaultBreakpoint(string) |
string |
null |
Default breakpoint when no page sets one |
defaultShowRecordActions(bool) |
bool |
null |
Default visibility of the actions footer |
defaultShowBulkSelection(bool) |
bool |
null |
Default visibility of the bulk checkbox |
Configuration Cascade
Each setting resolves through a four-level cascade:
responsiveTable()method on theListRecordspage (highest priority)$responsiveBreakpointproperty on theListRecordspage (breakpoint only)- Plugin defaults on
FilamentResponsiveTablePluginin the Panel Provider - Config file —
config/filament-responsive-table.php(lowest priority)
The method always wins over the property, which wins over plugin defaults, which win over the config file.
Default Config File
// config/filament-responsive-table.php return [ 'breakpoint' => 'md', 'show_record_actions' => true, 'show_bulk_selection' => false, ];
Full Example
use Filament\Resources\Pages\ListRecords; use Wezlo\FilamentResponsiveTable\Concerns\HasResponsiveTable; use Wezlo\FilamentResponsiveTable\ResponsiveTableConfiguration; class ListOrders extends ListRecords { use HasResponsiveTable; protected static string $resource = OrderResource::class; public function responsiveTable(ResponsiveTableConfiguration $config): ResponsiveTableConfiguration { return $config ->breakpoint('lg') ->except(['id']) ->cardTitle(fn ($record) => "#{$record->number}") ->showRecordActions() ->showBulkSelection(); } }
The resource's table() method stays unchanged — columns, filters, search, header actions, record actions, and bulk actions all carry over to the card view automatically.
How It Works
- The
HasResponsiveTabletrait overridescontent()on theListRecordspage to render a single wrapper view that contains both the native Filament table (via$this->getTable()->render()) and a card stack generated from the same columns. - The wrapper
<div>carriesdata-breakpoint="<bp>". A small shipped stylesheet has static@mediarules — at the configured breakpoint it hides the table and shows the cards, and vice-versa above it. Because the rules are static CSS (not Tailwind utilities), Tailwind's JIT scan isn't required for visibility toggling. - Each card pulls its columns from
$this->getTable()->getVisibleColumns(), then appliesonly/except. Columns are cloned per record ($column->getClone()->record($record)) so the same render pipeline used by the desktop table — badges, icons, date formatting, images — produces the card values. - Record actions are cloned per record (
$action->getClone()->record($record)) and filtered byisHidden(), mirroring the pattern in Filament's own table Blade view. - The desktop table is Filament's native
Table::render()output — search, filters, sorting, pagination, bulk actions, and row actions all work exactly as before.
CSS Classes
All elements use fi-responsive-table-* prefixed classes for targeted styling:
| Class | Element |
|---|---|
fi-responsive-table |
Root wrapper (carries data-breakpoint) |
fi-responsive-table-desktop |
Wraps Filament's native table |
fi-responsive-table-cards |
Wraps the card stack |
fi-responsive-table-cards-list |
Inner flex container for cards |
fi-responsive-table-card |
Individual card |
fi-responsive-table-card-header |
Card title + optional checkbox bar |
fi-responsive-table-card-title |
Title text |
fi-responsive-table-card-checkbox |
Bulk-selection checkbox |
fi-responsive-table-card-body |
<dl> grid of label/value pairs |
fi-responsive-table-card-field |
One label/value pair (uses display: contents) |
fi-responsive-table-card-field-label |
Column label (<dt>) |
fi-responsive-table-card-field-value |
Rendered column value (<dd>) |
fi-responsive-table-card-footer |
Record-actions footer |
Override any of these in your theme CSS to customize the card appearance.
License
MIT
wezlo/filament-responsive-table 适用场景与选型建议
wezlo/filament-responsive-table 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 77 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 04 月 22 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「mobile」 「responsive」 「laravel」 「table」 「cards」 「filament」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 wezlo/filament-responsive-table 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 wezlo/filament-responsive-table 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 wezlo/filament-responsive-table 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Beyonic PHP Library
ResponsiveImages Plugin for October CMS
TYPO3 extension for sending responsive email templates
The skeleton application for NativePHP for Mobile.
PHP SDK for Mobile Message SMS API
Responsive attributes addon for Bear Framework
统计信息
- 总下载量: 77
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 33
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-04-22