Repeater
The repeater renders a repeatable group of fields. Each row is its own copy of the schema, and the
field submits an array of row objects — one object per row, keyed by the child field names. Create one
with Repeater::make() and define the row template with ->schema().
Repeater::make('items', 'Line items') ->schema([ TextInput::make('name', 'Name')->required(), TextInput::make('qty', 'Qty')->rules(['numeric']), ]) ->minItems(1) ->maxItems(5) ->reorderable() ->addLabel('Add line') ->defaultItems(1)- addLabel:"Add line"
- columnWidth:"md"
- conditions:null
- defaultItems:1
- dependsOnAny:false
- dependsOnKeys:null
- disabled:false
- editablePrefill:false
- helperText:null
- hidden:false
- itemLabel:null
- label:"Line items"
- layout:"stack"
- maxItems:5
- minItems:1
- name:"items"
- prefillRefreshOn:null
- prefillResetOn:null
- readOnly:false
- reorderable:true
- required:false
- resizableColumns:false
- resizeIndicator:false
- rowActions:null
- tooltip:null
- value:null
- autoComplete:null
- autoFocus:false
- columnWidth:"md"
- conditions:null
- dependsOnAny:false
- dependsOnKeys:null
- disabled:false
- editablePrefill:false
- helperText:null
- hidden:false
- label:"Name"
- name:"name"
- placeholder:null
- prefillRefreshOn:null
- prefillResetOn:null
- prefix:null
- readOnly:false
- required:true
- suffix:null
- tabIndex:null
- tooltip:null
- type:null
- value:null
- autoComplete:null
- autoFocus:false
- columnWidth:"md"
- conditions:null
- dependsOnAny:false
- dependsOnKeys:null
- disabled:false
- editablePrefill:false
- helperText:null
- hidden:false
- label:"Qty"
- name:"qty"
- placeholder:null
- prefillRefreshOn:null
- prefillResetOn:null
- prefix:null
- readOnly:false
- required:false
- suffix:null
- tabIndex:null
- tooltip:null
- type:null
- value:null
Schema
Section titled “Schema”->schema() takes the array of fields that make up a single row. Each child is a normal field, so it
keeps its own label, placeholder, default value, and rules. The example above submits as:
['items' => [['name' => 'Widget', 'qty' => '3'], ['name' => 'Gadget', 'qty' => '1']]]Row counts
Section titled “Row counts”->minItems() and ->maxItems() bound how many rows the form accepts; both are enforced as
array-level validation rules. ->defaultItems() sets how many empty rows a fresh form starts with
(default 1).
Repeater::make('items', 'Line items') ->schema([TextInput::make('name', 'Name')]) ->minItems(1) ->maxItems(5) ->defaultItems(2);Reordering
Section titled “Reordering”Rows are reorderable by default through up/down controls. Pass ->reorderable(false) to fix the
order.
Repeater::make('items', 'Line items') ->schema([TextInput::make('name', 'Name')]) ->reorderable(false);Table layout
Section titled “Table layout”Rows stack by default — each row is a full block of stacked fields. Call ->table() to lay rows out
as a table instead: the schema fields become columns, a shared header of the field labels sits above
the rows, and each cell renders the input alone (the field’s own label moves up into the header).
Repeater::make('items', 'Line items') ->schema([ TextInput::make('name', 'Name'), TextInput::make('qty', 'Qty')->rules(['numeric']), ]) ->table();Reorder controls (↑↓) sit on the left of each row and the row actions on the right; once a row carries more than one action they collapse into a ⋯ menu. Reordering slides each row to its new position, and the table scrolls horizontally on narrow screens. The slide animation is skipped when the viewer prefers reduced motion.
Call ->resizableColumns() to let the user drag column borders to resize them; pass
showIndicator: true to surface a drag handle on each border.
Repeater::make('items', 'Line items') ->schema([ TextInput::make('name', 'Name'), TextInput::make('qty', 'Qty')->rules(['numeric']), ]) ->table() ->resizableColumns(showIndicator: true);Row actions
Section titled “Row actions”Every row carries an action menu. By default it holds just Remove (hidden while the row is at
minItems). Pass ->rowActions() to declare the menu yourself, including the built-in Duplicate
that clones a row in place. A single action renders inline; two or more collapse into a ⋯ menu. The
same menu renders in both the stacked and table layouts — reorder controls stay separate.
Repeater::make('items', 'Line items') ->schema([ TextInput::make('name', 'Name'), TextInput::make('qty', 'Qty')->rules(['numeric']), ]) ->rowActions([ RowAction::duplicate(), RowAction::remove()->label('Delete'), ]);- addLabel:null
- columnWidth:"md"
- conditions:null
- defaultItems:1
- dependsOnAny:false
- dependsOnKeys:null
- disabled:false
- editablePrefill:false
- helperText:null
- hidden:false
- itemLabel:null
- label:"Line items"
- layout:"stack"
- maxItems:null
- minItems:null
- name:"items"
- prefillRefreshOn:null
- prefillResetOn:null
- readOnly:false
- reorderable:true
- required:false
- resizableColumns:false
- resizeIndicator:false
- tooltip:null
- value:null
- autoComplete:null
- autoFocus:false
- columnWidth:"md"
- conditions:null
- dependsOnAny:false
- dependsOnKeys:null
- disabled:false
- editablePrefill:false
- helperText:null
- hidden:false
- label:"Name"
- name:"name"
- placeholder:null
- prefillRefreshOn:null
- prefillResetOn:null
- prefix:null
- readOnly:false
- required:false
- suffix:null
- tabIndex:null
- tooltip:null
- type:null
- value:null
- autoComplete:null
- autoFocus:false
- columnWidth:"md"
- conditions:null
- dependsOnAny:false
- dependsOnKeys:null
- disabled:false
- editablePrefill:false
- helperText:null
- hidden:false
- label:"Qty"
- name:"qty"
- placeholder:null
- prefillRefreshOn:null
- prefillResetOn:null
- prefix:null
- readOnly:false
- required:false
- suffix:null
- tabIndex:null
- tooltip:null
- type:null
- value:null
RowAction::duplicate() and RowAction::remove() are the built-ins; chain ->label(), ->icon(), or
->destructive() to customise each. Remove is hidden automatically while the row sits at minItems.
Pass an empty array — ->rowActions([]) — to drop the menu entirely.
Labels
Section titled “Labels”->addLabel() sets the text on the button that appends a row (default “Add”). ->itemLabel() sets a
per-row heading shown above each row’s fields.
Repeater::make('items', 'Line items') ->schema([TextInput::make('name', 'Name')]) ->addLabel('Add line') ->itemLabel('Line');Validation
Section titled “Validation”Each child field’s rules apply to every row through the items.*.field wildcard, so a child marked
->required() is required in each row and an error points at the offending row. The array-level
minItems/maxItems rules validate the number of rows independently of the per-row rules. See
Validation for how field rules are resolved.
Row-scoped conditions
Section titled “Row-scoped conditions”Conditional rules on a child field resolve against the other fields in the same row first, falling
back to form-level values. So visibleWhen, requiredWhen, readOnlyWhen, and disabledWhen on a
row field compare against its siblings, and each row evaluates independently — the same client-side and
on the server. See Conditional fields for the condition DSL.
Repeater::make('items', 'Line items') ->schema([ Select::make('type', 'Type')->options(['Fixed' => 'fixed', 'Hourly' => 'hourly']), NumberInput::make('hours', 'Hours') ->visibleWhen('type', 'hourly') ->requiredWhen('type', 'hourly'), ]);Not yet supported (v1)
Section titled “Not yet supported (v1)”These are follow-ups, not part of the first release:
- Nested repeaters (a repeater inside a repeater row).
- Relationship auto-save (persisting rows straight to a related model).
Common options
Section titled “Common options”Repeater shares label, required, disabled, read-only, and visibility options with every field — see
Fields. For validation and conditional behavior, see
Validation and Conditional fields.