K

Forms

Repeater

Repeater manages repeated groups of fields and can persist hasMany relationship data.

Repeater preview
On this page

Repeater manages repeated groups of fields and can persist hasMany relationship data.

Basic Usage

use NyonCode\WireForms\Components\Repeater;
use NyonCode\WireForms\Components\TextInput;
 
Repeater::make('contacts')
->schema([
TextInput::make('name')->required(),
TextInput::make('email')->email(),
])

Relationship Mode

Use relationship() when the repeater should save related records.

Repeater::make('contacts')
->relationship('contacts')
->schema([
TextInput::make('name')->required(),
TextInput::make('email')->email(),
])
->addable()
->deletable()
->reorderable()

Limits and UX Controls

Repeater::make('contacts')
->minItems(1)
->maxItems(10)
->addButtonLabel('Add contact')
->collapsible()
->itemLabel(fn (array $state) => $state['name'] ?? null) // named items: "#1 Ada"

Named items

By default each item block is headed by its number (#1, #2, …). Pass itemLabel() a static string or a closure of the item's state (and index) to show a name next to the number — handy for identifying collapsed items. The label re-renders on the item's reactive cycle, so pair it with a ->live() field to update it as the user types.

Repeater::make('contacts')
->schema([TextInput::make('name')->live()])
->itemLabel(fn (array $state, int $index) => $state['name'] ?? "Contact #{$index}");
Method Purpose
addable() Allow new items
deletable() Allow item removal
reorderable() Allow manual reordering
collapsible() Let users collapse item blocks
collapsed() Start items collapsed
minItems() / maxItems() Constrain collection size
addable(bool) Allow adding new items (default true)
deletable(bool) Allow removing items (default true)
reorderable(bool) Allow drag-to-reorder (default false)
collapsible(bool) Allow collapsing item blocks
collapsed(bool) Start all items collapsed (implies collapsible)
minItems(int|null) Minimum item count
maxItems(int|null) Maximum item count
addButtonLabel(string|null) Label on the add button
itemLabel(string|Closure|null) Name shown next to each item's number (fn(array $state, int $index): ?string)
disabled(bool|Closure) Disable add/delete/reorder controls
mutateRelationshipDataBeforeSaveUsing(Closure) Transform item data before persistence

Per-Item Reactivity

Reactive behavior inside a repeater resolves per item: afterStateUpdated(), live validation, field actions, remote select search and conditional visibility all read the item's own state bag, and $get/$set are scoped to that item.

Repeater::make('contacts')->schema([
Select::make('type')->options(['email' => 'Email', 'other' => 'Other'])->live(),
TextInput::make('other_detail')->visibleWhen('type', 'other'),
])

Here other_detail shows only in the rows whose own type is other — flipping row 2's select never affects row 1. See Reactive Fields for the full accessor reference.

When to Use It

Use Repeater when a single form owns a small to medium collection of related child records and the user should manage them inline.

If the child records need independent filtering, pagination, or heavy workflows, give them their own table or screen.