[4.x] Feat: Add compact option to table repeater (#17411)

* Feat: Add streamlined option to table repeater

* Feat: Replace streamlined table repeater option with compact alternative

* Add padding to compact repeater infolist entries

* clean up

---------

Co-authored-by: Dan Harrin <git@danharrin.com>
This commit is contained in:
oddvalue
2025-09-18 21:57:11 +01:00
committed by GitHub
co-authored by Dan Harrin
parent b56ef3a2fc
commit 41a4e495d5
10 changed files with 175 additions and 4 deletions
@@ -1030,6 +1030,49 @@ class FieldsDemo extends Component implements HasActions, HasSchemas
],
]),
]),
Group::make()
->id('repeaterTableCompact')
->extraAttributes([
'class' => 'p-16 max-w-5xl',
])
->schema([
Repeater::make('repeaterTable')
->label('Members')
->table([
Repeater\TableColumn::make('Name'),
Repeater\TableColumn::make('Role'),
])
->compact()
->schema([
TextInput::make('name')->required(),
Select::make('role')
->options([
'member' => 'Member',
'administrator' => 'Administrator',
'owner' => 'Owner',
])
->required(),
])
->columns(2)
->default([
[
'name' => 'Dan Harrin',
'role' => 'owner',
],
[
'name' => 'Ryan Chandler',
'role' => 'administrator',
],
[
'name' => 'Zep Fietje',
'role' => 'member',
],
[
'name' => null,
'role' => null,
],
]),
]),
Group::make()
->id('repeaterReorderableWithButtons')
->extraAttributes([
Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

+9
View File
@@ -986,6 +986,15 @@ export default {
deviceScaleFactor: 3,
},
},
'forms/fields/repeater/table-compact': {
url: 'forms/fields',
selector: '#repeaterTableCompact',
viewport: {
width: 1920,
height: 640,
deviceScaleFactor: 3,
},
},
'forms/fields/repeater/reorderable-with-buttons': {
url: 'forms/fields',
selector: '#repeaterReorderableWithButtons',
+36
View File
@@ -659,6 +659,42 @@ TableColumn::make('Name')
->width('200px')
```
### Compact table repeaters
You can make table repeaters more compact by using the `compact()` method, to fit more data in a smaller space:
```php
use Filament\Forms\Components\Repeater;
Repeater::make('members')
->table([
// ...
])
->compact()
->schema([
// ...
])
```
Optionally, you may pass a boolean value to control if the table repeater should be compact or not:
```php
use Filament\Forms\Components\Repeater;
Repeater::make('members')
->table([
// ...
])
->compact(FeatureFlag::active())
->schema([
// ...
])
```
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `compact()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
<AutoScreenshot name="forms/fields/repeater/table-compact" alt="Repeater with a compact table layout" version="4.x" />
## Repeater validation
As well as all rules listed on the [validation](validation) page, there are additional rules that are specific to repeaters.
@@ -242,7 +242,7 @@
@apply @xl:hidden;
}
& .fi-in-entry-label-content {
& .fi-in-entry-label {
@apply @xl:hidden;
}
}
@@ -253,6 +253,30 @@
@apply @xl:px-3 @xl:py-2;
}
}
&.fi-compact {
& > table {
& > tbody {
& > tr {
& > td {
@apply @xl:border-gray-200 @xl:px-0 @xl:py-1 @xl:dark:border-white/5 @xl:[&:not(:first-of-type)]:border-s @xl:[&:not(:last-of-type)]:border-e;
}
}
}
}
& .fi-input-wrp {
@apply @xl:bg-transparent! @xl:shadow-none @xl:ring-0!;
}
& .fi-fo-field-wrp-error-message {
@apply @xl:px-3 @xl:pb-2;
}
& .fi-in-entry-content {
@apply @xl:px-3;
}
}
}
@supports not (container-type: inline-size) {
@@ -288,7 +312,7 @@
@apply lg:hidden;
}
& .fi-in-entry-label-content {
& .fi-in-entry-label {
@apply lg:hidden;
}
}
@@ -299,6 +323,30 @@
@apply lg:px-3 lg:py-2;
}
}
&.fi-compact {
& > table {
& > tbody {
& > tr {
& > td {
@apply lg:border-gray-200 lg:px-0 lg:py-1 lg:dark:border-white/5 lg:[&:not(:first-of-type)]:border-s lg:[&:not(:last-of-type)]:border-e;
}
}
}
}
& .fi-input-wrp {
@apply lg:bg-transparent! lg:shadow-none lg:ring-0!;
}
& .fi-fo-field-wrp-error-message {
@apply lg:px-3 lg:pb-2;
}
& .fi-in-entry-content {
@apply lg:px-3;
}
}
}
& .fi-fo-table-repeater-add {
@@ -29,13 +29,18 @@
$statePath = $getStatePath();
$tableColumns = $getTableColumns();
$isCompact = $isCompact();
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
{{ $attributes
->merge($getExtraAttributes(), escape: false)
->class(['fi-fo-table-repeater']) }}
->class([
'fi-fo-table-repeater',
'fi-compact' => $isCompact,
]) }}
>
@if (count($items))
<table class="fi-absolute-positioning-context">
@@ -8,6 +8,7 @@ use Filament\Forms\Components\Repeater\TableColumn;
use Filament\Forms\View\FormsIconAlias;
use Filament\Schemas\Components\Component;
use Filament\Schemas\Components\Concerns\CanBeCollapsed;
use Filament\Schemas\Components\Concerns\CanBeCompact;
use Filament\Schemas\Components\Concerns\HasContainerGridLayout;
use Filament\Schemas\Components\Contracts\CanConcealComponents;
use Filament\Schemas\Components\Contracts\HasExtraItemActions;
@@ -32,6 +33,7 @@ use function Filament\Forms\array_move_before;
class Repeater extends Field implements CanConcealComponents, HasExtraItemActions
{
use CanBeCollapsed;
use CanBeCompact;
use Concerns\CanBeCloned;
use Concerns\CanGenerateUuids;
use Concerns\CanLimitItemsLength;
+1 -1
View File
File diff suppressed because one or more lines are too long
@@ -295,6 +295,34 @@ it('can use select options from an enum with `disableOptionsWhenSelectedInSiblin
$undoRepeaterFake();
});
it('can be compact', function (): void {
$repeater = Repeater::make('members')
->schema([
TextInput::make('name'),
])
->compact();
expect($repeater->isCompact())->toBeTrue();
});
it('can conditionally be compact', function (): void {
$repeater = Repeater::make('members')
->schema([
TextInput::make('name'),
])
->compact(fn () => true);
expect($repeater->isCompact())->toBeTrue();
$repeater = Repeater::make('members')
->schema([
TextInput::make('name'),
])
->compact(fn () => false);
expect($repeater->isCompact())->toBeFalse();
});
it('can use arguments to hide the delete action', function (): void {
$undoRepeaterFake = Repeater::fake();