icetalker/filament-table-repeater
Installation
composer require icetalker/filament-table-repeater
Publish the config (if needed):
php artisan vendor:publish --provider="Icetalker\FilamentTableRepeater\FilamentTableRepeaterServiceProvider"
First Use Case
Replace a standard Repeater in your Filament form with TableRepeater:
use Icetalker\FilamentTableRepeater\TableRepeater;
TableRepeater::make('items')
->columns([
TextInput::make('name'),
Select::make('status')->options(['active', 'inactive']),
])
->columnSpanFull()
->required(),
Where to Look First
Basic Table Repeater
TableRepeater::make('features')
->columns([
Toggle::make('is_active'),
TextInput::make('description'),
])
->columnSpanFull()
->defaultItems(1);
Nested Repeaters
Use Repeater inside TableRepeater for hierarchical data:
TableRepeater::make('steps')
->columns([
Repeater::make('sub_steps')
->schema([
TextInput::make('title'),
]),
]);
Dynamic Columns Conditionally render columns based on logic:
TableRepeater::make('products')
->columns([
TextInput::make('name'),
Select::make('category')->options(fn () => ProductCategory::all()),
])
->columnsHiddenByDefault(['category'])
->extraColumns([
TextInput::make('sku')->visible(fn ($record) => $record->category === 'premium'),
]);
Integration with Filament Resources
public static function form(Form $form): Form
{
return $form
->schema([
TableRepeater::make('tags')
->columns([
TextInput::make('name'),
TextInput::make('color')->mask(fn ($state) => '#' . str_pad(dechex(crc32($state)), 6, '0', STR_PAD_LEFT)),
]),
]);
}
Validation & Rules Apply validation per row or globally:
TableRepeater::make('prices')
->columns([
NumberInput::make('value')
->required()
->minValue(0),
])
->validateItems(fn (array $items) => [
'*.value' => ['required', 'min:0'],
]);
Customizing Table Layout Override default table styling via CSS or config:
// config/filament-table-repeater.php
'table' => [
'class' => 'min-w-full divide-y divide-gray-200 dark:divide-gray-700',
],
Bulk Actions Add row-level actions (e.g., delete, duplicate):
TableRepeater::make('tasks')
->columns([
// ... columns ...
])
->actions([
Action::make('delete')
->icon('heroicon-o-trash')
->action(fn (array $record) => $this->removeItem($record)),
]);
Server-Side Processing
For large datasets, use livewire:load or livewire:update to lazy-load rows:
TableRepeater::make('logs')
->columns([
// ... columns ...
])
->wireModel('logs')
->wireEvents('livewire:update');
Exporting Data
Combine with Filament’s Table export features:
use Filament\Tables\Actions\ExportAction;
ExportAction::make()
->label('Export Items')
->filename('items.csv')
->query(fn () => $this->query)
->columns([
// Map TableRepeater columns to export columns
]);
Column Span Issues
columnSpanFull() or adjust CSS:
TableRepeater::make('items')->columnSpanFull()->columns([...]);
Nested Repeater Rendering
Repeater inside TableRepeater may not render correctly.Repeater uses schema() and not columns():
Repeater::make('nested_items')->schema([...]) // Correct
Repeater::make('nested_items')->columns([...]) // Avoid
Livewire Model Binding
wireModel aren’t reflected immediately.wire:model.live or trigger updates manually:
$this->dispatch('refreshTableRepeater');
Validation Errors
validateItems():
->validateItems(fn (array $items) => [
'*.required_field' => 'required',
]);
Dark Mode Styling
'table' => [
'class' => 'dark:divide-gray-700 dark:border-gray-700',
],
Inspect Rendered HTML Use browser dev tools to check if columns are rendered correctly. Look for:
tr or td elements.colspan attributes.Log Wire Model Data
Debug wireModel binding:
protected function getListeners(): array
{
return [
'items' => ['refreshItems'],
];
}
public function refreshItems()
{
\Log::info('Current items:', $this->items);
}
Check for Conflicts
!important overrides.Custom Column Types
Extend TableRepeater to support custom column logic:
TableRepeater::make('custom_data')
->columns([
CustomColumn::make('metadata')
->renderUsing(fn ($state) => json_encode($state)),
]);
Hooks for Pre/Post Processing Use Filament’s hooks to modify data before saving:
use Filament\Forms\Concerns\InteractsWithForms;
public function save(Form $form): void
{
$form->fill();
$this->processRepeaterData($form->getModel()->items);
$form->save();
}
Override Blade Views Customize the table layout by publishing views:
php artisan vendor:publish --tag="filament-table-repeater-views"
Then modify resources/views/vendor/filament-table-repeater/....
Add Global JavaScript Extend functionality with Alpine.js or vanilla JS:
Filament::serving(function () {
Filament::registerScript('filament-table-repeater-extra', <<<'JS'
document.addEventListener('filament-table-repeater-ready', function () {
// Custom logic here
});
JS);
});
How can I help you explore Laravel packages today?