Repeater
Overview
The repeater component allows you to output a JSON array of repeated form components.
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
Repeater::make('members')
->schema([
TextInput::make('name')->required(),
Select::make('role')
->options([
'member' => 'Member',
'administrator' => 'Administrator',
'owner' => 'Owner',
])
->required(),
])
->columns(2)
We recommend that you store repeater data with a JSON
column in your database. Additionally, if you're using Eloquent, make sure that column has an array
cast.
As evident in the above example, the component schema can be defined within the schema()
method of the component:
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\TextInput;
Repeater::make('members')
->schema([
TextInput::make('name')->required(),
// ...
])
If you wish to define a repeater with multiple schema blocks that can be repeated in any order, please use the builder.
Setting empty default items
Repeaters may have a certain number of empty items created by default, using the defaultItems()
method:
use Filament\Forms\Components\Repeater;
Repeater::make('members')
->schema([
// ...
])
->defaultItems(3)
Note that these default items are only created when the form is loaded without existing data. Inside panel resources this only works on Create Pages, as Edit Pages will always fill the data from the model.
Adding items
An action button is displayed below the repeater to allow the user to add a new item.
Setting the add action button's label
You may set a label to customize the text that should be displayed in the button for adding a repeater item, using the addActionLabel()
method:
use Filament\Forms\Components\Repeater;
Repeater::make('members')
->schema([
// ...
])
->addActionLabel('Add member')
Preventing the user from adding items
You may prevent the user from adding items to the repeater using the addable(false)
method:
use Filament\Forms\Components\Repeater;
Repeater::make('members')
->schema([
// ...
])
->addable(false)
Deleting items
An action button is displayed on each item to allow the user to delete it.
Preventing the user from deleting items
You may prevent the user from deleting items from the repeater using the deletable(false)
method:
use Filament\Forms\Components\Repeater;
Repeater::make('members')
->schema([
// ...
])
->deletable(false)
Reordering items
A button is displayed on each item to allow the user to drag and drop to reorder it in the list.
Preventing the user from reordering items
You may prevent the user from reordering items from the repeater using the reorderable(false)
method:
use Filament\Forms\Components\Repeater;
Repeater::make('members')
->schema([
// ...
])
->reorderable(false)
Reordering items with buttons
You may use the reorderableWithButtons()
method to enable reordering items with buttons to move the item up and down:
use Filament\Forms\Components\Repeater;
Repeater::make('members')
->schema([
// ...
])
->reorderableWithButtons()
Preventing reordering with drag and drop
You may use the reorderableWithDragAndDrop(false)
method to prevent items from being ordered with drag and drop:
use Filament\Forms\Components\Repeater;
Repeater::make('members')
->schema([
// ...
])
->reorderableWithDragAndDrop(false)
Collapsing items
The repeater may be collapsible()
to optionally hide content in long forms:
use Filament\Forms\Components\Repeater;
Repeater::make('qualifications')
->schema([
// ...
])
->collapsible()
You may also collapse all items by default:
use Filament\Forms\Components\Repeater;
Repeater::make('qualifications')
->schema([
// ...
])
->collapsed()
Cloning items
You may allow repeater items to be duplicated using the cloneable()
method:
use Filament\Forms\Components\Repeater;
Repeater::make('qualifications')
->schema([
// ...
])
->cloneable()
Integrating with an Eloquent relationship
If you're building a form inside your Livewire component, make sure you have set up the form's model. Otherwise, Filament doesn't know which model to use to retrieve the relationship from.
You may employ the relationship()
method of the Repeater
to configure a HasMany
relationship. Filament will load the item data from the relationship, and save it back to the relationship when the form is submitted. If a custom relationship name is not passed to relationship()
, Filament will use the field name as the relationship name:
use Filament\Forms\Components\Repeater;
Repeater::make('qualifications')
->relationship()
->schema([
// ...
])
When using disabled()
with relationship()
, ensure that disabled()
is called before relationship()
. This ensures that the dehydrated()
call from within relationship()
is not overridden by the call from disabled()
:
use Filament\Forms\Components\Repeater;
Repeater::make('qualifications')
->disabled()
->relationship()
->schema([
// ...
])
Reordering items in a relationship
By default, reordering relationship repeater items is disabled. This is because your related model needs a sort
column to store the order of related records. To enable reordering, you may use the orderColumn()
method, passing in a name of the column on your related model to store the order in:
use Filament\Forms\Components\Repeater;
Repeater::make('qualifications')
->relationship()
->schema([
// ...
])
->orderColumn('sort')
If you use something like spatie/eloquent-sortable
with an order column such as order_column
, you may pass this in to orderColumn()
:
use Filament\Forms\Components\Repeater;
Repeater::make('qualifications')
->relationship()
->schema([
// ...
])
->orderColumn('order_column')
Integrating with a BelongsToMany
Eloquent relationship
There is a common misconception that using a BelongsToMany
relationship with a repeater is as simple as using a HasMany
relationship. This is not the case, as a BelongsToMany
relationship requires a pivot table to store the relationship data. The repeater saves its data to the related model, not the pivot table. Therefore, if you want to map each repeater item to a row in the pivot table, you must use a HasMany
relationship with a pivot model to use a repeater with a BelongsToMany
relationship.
Imagine you have a form to create a new Order
model. Each order belongs to many Product
models, and each product belongs to many orders. You have a order_product
pivot table to store the relationship data. Instead of using the products
relationship with the repeater, you should create a new relationship called orderProducts
on the Order
model, and use that with the repeater:
use Illuminate\Database\Eloquent\Relations\HasMany;
public function orderProducts(): HasMany
{
return $this->hasMany(OrderProduct::class);
}
If you don't already have an OrderProduct
pivot model, you should create that, with inverse relationships to Order
and Product
:
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\Pivot;
class OrderProduct extends Pivot
{
public function order(): BelongsTo
{
return $this->belongsTo(Order::class);
}
public function product(): BelongsTo
{
return $this->belongsTo(Product::class);
}
}
Please ensure that your pivot model has a primary key column, like
id
, to allow Filament to keep track of which repeater items have been created, updated and deleted.
Now you can use the orderProducts
relationship with the repeater, and it will save the data to the order_product
pivot table:
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
Repeater::make('orderProducts')
->relationship()
->schema([
Select::make('product_id')
->relationship('product', 'name')
->required(),
// ...
])
Mutating related item data before filling the field
You may mutate the data for a related item before it is filled into the field using the mutateRelationshipDataBeforeFillUsing()
method. This method accepts a closure that receives the current item's data in a $data
variable. You must return the modified array of data:
use Filament\Forms\Components\Repeater;
Repeater::make('qualifications')
->relationship()
->schema([
// ...
])
->mutateRelationshipDataBeforeFillUsing(function (array $data): array {
$data['user_id'] = auth()->id();
return $data;
})
Mutating related item data before creating
You may mutate the data for a new related item before it is created in the database using the mutateRelationshipDataBeforeCreateUsing()
method. This method accepts a closure that receives the current item's data in a $data
variable. You can choose to return either the modified array of data, or null
to prevent the item from being created:
use Filament\Forms\Components\Repeater;
Repeater::make('qualifications')
->relationship()
->schema([
// ...
])
->mutateRelationshipDataBeforeCreateUsing(function (array $data): array {
$data['user_id'] = auth()->id();
return $data;
})
Mutating related item data before saving
You may mutate the data for an existing related item before it is saved in the database using the mutateRelationshipDataBeforeSaveUsing()
method. This method accepts a closure that receives the current item's data in a $data
variable. You can choose to return either the modified array of data, or null
to prevent the item from being saved:
use Filament\Forms\Components\Repeater;
Repeater::make('qualifications')
->relationship()
->schema([
// ...
])
->mutateRelationshipDataBeforeSaveUsing(function (array $data): array {
$data['user_id'] = auth()->id();
return $data;
})