表格

布局

传统表格布局的问题

传统的表格因响应性差而臭名昭著。在移动端上,渲染水平方向较长的内容时,灵活性有限:

  • 允许用户水平滚动以查看更多表格内容
  • 在较小的设备上隐藏不重要的列

这两中在 Filament 中都能实现。当表溢出时,它们会自动水平滚动,你可以选择根据浏览器的响应断点显示和隐藏列。为此,你可以使用 visibleFrom()hiddenFrom() 方法:

use Filament\Tables\Columns\TextColumn;

TextColumn::make('slug')
    ->visibleFrom('md')

这很好,但仍然存在一个明显的问题 —— 在移动设备上,用户如果不滚动,就无法一次看到表格行中的很多信息。

Filament offers two solutions to this problem:

  1. Simple stacking - Use stackedOnMobile() to automatically stack all cells vertically on mobile without changing your column definitions
  2. Custom layouts - Use Split, Stack, and other layout components for fine-grained control over how content appears at each breakpoint

Stacking table cells on mobile

The simplest way to make your table responsive is to use the stackedOnMobile() method on the table. This automatically converts the traditional horizontal table layout into a vertical card-like layout on mobile screens, while preserving the standard table appearance on larger screens:

use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return $table
        ->columns([
            TextColumn::make('name')
                ->searchable()
                ->sortable(),
            TextColumn::make('email'),
            TextColumn::make('phone'),
            TextColumn::make('job'),
        ])
        ->stackedOnMobile();
}
Table with stacked mobile layout on desktop
Table with stacked mobile layout on mobile

On mobile, each row displays as a card with the column label above its value. If you have sortable columns, a sort dropdown appears at the top of the table on mobile, allowing users to sort without the traditional header row. Bulk selection is also supported, with a checkbox appearing in the header area.

This approach works well when you want a quick responsive solution without restructuring your columns. However, for more complex layouts or fine-grained control over how content appears at different breakpoints, you may prefer to use the layout components described below.

Custom column layouts

Filament lets you build responsive table-like interfaces, without touching HTML or CSS. These layouts let you define exactly where content appears in a table row, at each responsive breakpoint.

Table with responsive layout
Table with responsive layout on mobile

允许用户在移动端堆叠列

我们来引入一个组件 - Split:

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\TextColumn;

Split::make([
    ImageColumn::make('avatar')
        ->circular(),
    TextColumn::make('name')
        ->weight(FontWeight::Bold)
        ->searchable()
        ->sortable(),
    TextColumn::make('email'),
])
Table with a split layout
Table with a split layout on mobile

Split 组件用于包裹列字段,并允许它们在移动设备上堆叠。

默认情况下,Split 中的列将始终并排显示。但是你可以选择一个该行为开始(form())的响应式断点。在此之前,列将堆叠在一起:

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

Split::make([
    ImageColumn::make('avatar')
        ->circular(),
    TextColumn::make('name')
        ->weight(FontWeight::Bold)
        ->searchable()
        ->sortable(),
    TextColumn::make('email'),
])->from('md')

本例中,这些列只有在 md 断点以上的设备中水平并排展示:

Table with a split layout on desktop
Table with a stacked layout on mobile

防止列创建空格

Split,就像表格列一样,会自动调整它们的空格,以确保每一列都有适当的分隔。你可以使用 grow(false) 来阻止这种情况发生。在这个例子中,我们将确保头像图片紧紧地贴在名称列上:

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

Split::make([
    ImageColumn::make('avatar')
        ->circular()
        ->grow(false),
    TextColumn::make('name')
        ->weight(FontWeight::Bold)
        ->searchable()
        ->sortable(),
    TextColumn::make('email'),
])

允许 grow() 的其他列将进行调整以消耗新释放的空间:

Table with a column that doesn't grow
Table with a column that doesn't grow on mobile

Split 中堆叠

在 Split 中,你可以将多列垂直堆叠在一起。这允许你在桌面端中在更少列中显示更多数据:

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

Split::make([
    ImageColumn::make('avatar')
        ->circular(),
    TextColumn::make('name')
        ->weight(FontWeight::Bold)
        ->searchable()
        ->sortable(),
    Stack::make([
        TextColumn::make('phone')
            ->icon('heroicon-m-phone'),
        TextColumn::make('email')
            ->icon('heroicon-m-envelope'),
    ]),
])
Table with a stack
Table with a stack on mobile

在移动设备上隐藏堆叠

与单个列类似,你可以根据浏览器的响应式断点选择隐藏堆叠。为此,你可以使用 visibleFrom() 方法:

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

Split::make([
    ImageColumn::make('avatar')
        ->circular(),
    TextColumn::make('name')
        ->weight(FontWeight::Bold)
        ->searchable()
        ->sortable(),
    Stack::make([
        TextColumn::make('phone')
            ->icon('heroicon-m-phone'),
        TextColumn::make('email')
            ->icon('heroicon-m-envelope'),
    ])->visibleFrom('md'),
])
Table with a stack
Table with no stack on mobile

对齐堆叠内容

默认情况下,堆叠中的列对齐到起始位置。你可以选择将堆叠中的列对齐到 Alignment::CenterAlignment::End

use Filament\Support\Enums\Alignment;
use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

Split::make([
    ImageColumn::make('avatar')
        ->circular(),
    TextColumn::make('name')
        ->weight(FontWeight::Bold)
        ->searchable()
        ->sortable(),
    Stack::make([
        TextColumn::make('phone')
            ->icon('heroicon-m-phone')
            ->grow(false),
        TextColumn::make('email')
            ->icon('heroicon-m-envelope')
            ->grow(false),
    ])
        ->alignment(Alignment::End)
        ->visibleFrom('md'),
])

请确保堆栈内的列已设置 grow(false),否则它们将拉伸以填充堆栈的整个宽度并遵循它们自己的对齐配置而不是堆栈的对齐配置。

Table with a stack aligned right

堆叠内容的间距

默认情况下,堆叠内容在列之间没有垂直 padding。要添加 padding,你可以使用 space() 方法,该方法接受 123,对应于 Tailwind 的间距比例:

use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\TextColumn;

Stack::make([
    TextColumn::make('phone')
        ->icon('heroicon-m-phone'),
    TextColumn::make('email')
        ->icon('heroicon-m-envelope'),
])->space(1)
Table with spaced stacked content

使用网格控制列宽

有时,当列字段包含很多内容时,使用 Split 会出现不一致的宽度。这是因为它内部是使用 Flexbox 驱动,并且每行独自控制分配多少空格给内容。

作为替代方案,你可以使用 Grid 布局,它使用 CSS 网格布局,允许你控制列宽:

use Filament\Tables\Columns\Layout\Grid;
use Filament\Tables\Columns\TextColumn;

Grid::make([
    'lg' => 2,
])
    ->schema([
        TextColumn::make('phone')
            ->icon('heroicon-m-phone'),
        TextColumn::make('email')
            ->icon('heroicon-m-envelope'),
    ])

lg 断点开始,这些列字段在网格内始终会消费同样的宽度。

Table with a grid column layout

你也可以在其他断点处自定义网格的列数:

use Filament\Tables\Columns\Layout\Grid;
use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\TextColumn;

Grid::make([
    'lg' => 2,
    '2xl' => 4,
])
    ->schema([
        Stack::make([
            TextColumn::make('name'),
            TextColumn::make('job'),
        ]),
        TextColumn::make('phone')
            ->icon('heroicon-m-phone'),
        TextColumn::make('email')
            ->icon('heroicon-m-envelope'),
    ])

你甚至可以控制每个组件在每个临界点所使用的网格列数:

use Filament\Tables\Columns\Layout\Grid;
use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\TextColumn;

Grid::make([
    'lg' => 2,
    '2xl' => 5,
])
    ->schema([
        Stack::make([
            TextColumn::make('name'),
            TextColumn::make('job'),
        ])->columnSpan([
            'lg' => 'full',
            '2xl' => 2,
        ]),
        TextColumn::make('phone')
            ->icon('heroicon-m-phone')
            ->columnSpan([
                '2xl' => 2,
            ]),
        TextColumn::make('email')
            ->icon('heroicon-m-envelope'),
    ])

可折叠内容

当你使用像 Split 或 Stack 这样的列布局时,你也可以添加可折叠的内容。当你不想一次性显示表中的所有数据,但仍然希望用户在需要访问时可以访问它,而无需调出当前页面时,这非常有用。

Split 和 Stack 组件可以设置为 collapsible(),同时还有一个专门的 Panel 组件,它提供了一个预设的背景颜色和边框半径,将可折叠内容与其他内容分开:

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Panel;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

[
    Split::make([
        ImageColumn::make('avatar')
            ->circular(),
        TextColumn::make('name')
            ->weight(FontWeight::Bold)
            ->searchable()
            ->sortable(),
    ]),
    Panel::make([
        Stack::make([
            TextColumn::make('phone')
                ->icon('heroicon-m-phone'),
            TextColumn::make('email')
                ->icon('heroicon-m-envelope'),
        ]),
    ])->collapsible(),
]

使用 collapsed(false) 方法,你可以让面板默认展开:

use Filament\Tables\Columns\Layout\Panel;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\TextColumn;

Panel::make([
    Split::make([
        TextColumn::make('phone')
            ->icon('heroicon-m-phone'),
        TextColumn::make('email')
            ->icon('heroicon-m-envelope'),
    ])->from('md'),
])->collapsed(false)
Table with collapsible content
Table with collapsible content on mobile

将记录排列到网格中

有时,你可能会发现你的数据更适合使用网格布局,而不是列表。Filament 也可以处理这种情况!

只需使用 $table->contentGrid() 方法:

use Filament\Tables\Columns\Layout\Stack;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return $table
        ->columns([
            Stack::make([
                // Columns
            ]),
        ])
        ->contentGrid([
            'md' => 2,
            'xl' => 3,
        ]);
}

本例中,这些行将会在网格中展示:

  • 在移动端,它们只显示在 1 列中。
  • md 断点开始,它们会显示成 2 列。
  • xl 断点开始,它们会显示成 3 列

这些设置完全是可自定义的,从 sm2xl 的任何临界点都能包含 112 列。

Table with grid layout
Table with grid layout on mobile

自定义 HTML

使用 View 组件,你可以将自定义 HTML 添加到你的表格中。它也可以设置成可折叠 collapsible()

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\Layout\View;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

[
    Split::make([
        ImageColumn::make('avatar')
            ->circular(),
        TextColumn::make('name')
            ->weight(FontWeight::Bold)
            ->searchable()
            ->sortable(),
    ]),
    View::make('users.table.collapsible-row-content')
        ->collapsible(),
]

然后,新建一个 /resources/views/users/table/collapsible-row-content.blade.php 文件,并添加 HTML。你可以使用 $getRecord() 访问表中的记录:

<p class="px-4 py-3 bg-gray-100 rounded-lg">
    <span class="font-medium">
        Email address:
    </span>

    <span>
        {{ $getRecord()->email }}
    </span>
</p>

嵌入其他组件

你甚至可以将列或者其他布局组件传入到 components() 方法:

use Filament\Support\Enums\FontWeight;
use Filament\Tables\Columns\Layout\Split;
use Filament\Tables\Columns\Layout\View;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;

[
    Split::make([
        ImageColumn::make('avatar')
            ->circular(),
        TextColumn::make('name')
            ->weight(FontWeight::Bold)
            ->searchable()
            ->sortable(),
    ]),
    View::make('users.table.collapsible-row-content')
        ->components([
            TextColumn::make('email')
                ->icon('heroicon-m-envelope'),
        ])
        ->collapsible(),
]

然后,在 Blade 文件中渲染组件:

<div class="px-4 py-3 bg-gray-100 rounded-lg">
    @foreach ($getComponents() as $layoutComponent)
        {{ $layoutComponent
            ->record($getRecord())
            ->recordKey($getRecordKey())
            ->rowLoop($getRowLoop())
            ->renderInLayout() }}
    @endforeach
</div>
Edit on GitHub

Still need help? Join our Discord community or open a GitHub discussion

Previous
Action