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
- itemLabel:null
- itemLabels:null
- label:"Line items"
- labelAction:null
- layout:"stack"
- maxItems:5
- minItems:1
- name:"items"
- nestedRowsKey:null
- 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
- copyable:false
- dependsOnAny:false
- dependsOnKeys:null
- disabled:false
- editablePrefill:false
- helperText:null
- label:"Name"
- labelAction:null
- name:"name"
- placeholder:null
- prefillRefreshOn:null
- prefillResetOn:null
- prefix:null
- prefixFieldName:null
- readOnly:false
- required:true
- suffix:null
- suffixFieldName:null
- tabIndex:null
- tooltip:null
- type:null
- value:null
- autoComplete:null
- autoFocus:false
- columnWidth:"md"
- conditions:null
- copyable:false
- dependsOnAny:false
- dependsOnKeys:null
- disabled:false
- editablePrefill:false
- helperText:null
- label:"Qty"
- labelAction:null
- name:"qty"
- placeholder:null
- prefillRefreshOn:null
- prefillResetOn:null
- prefix:null
- prefixFieldName:null
- readOnly:false
- required:false
- suffix:null
- suffixFieldName: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' => [ ['rowId' => '9f3c…', 'name' => 'Widget', 'qty' => '3'], ['rowId' => 'a2b1…', 'name' => 'Gadget', 'qty' => '1'],]]Every row carries a stable UUID under the reserved rowId key: rows filled from stored data keep
theirs, new rows get one when they are added, and it survives validation into your handle() data.
Row schemas must not declare their own rowId field.
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
- itemLabel:null
- itemLabels:null
- label:"Line items"
- labelAction:null
- layout:"stack"
- maxItems:null
- minItems:null
- name:"items"
- nestedRowsKey:null
- 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
- copyable:false
- dependsOnAny:false
- dependsOnKeys:null
- disabled:false
- editablePrefill:false
- helperText:null
- label:"Name"
- labelAction:null
- name:"name"
- placeholder:null
- prefillRefreshOn:null
- prefillResetOn:null
- prefix:null
- prefixFieldName:null
- readOnly:false
- required:false
- suffix:null
- suffixFieldName:null
- tabIndex:null
- tooltip:null
- type:null
- value:null
- autoComplete:null
- autoFocus:false
- columnWidth:"md"
- conditions:null
- copyable:false
- dependsOnAny:false
- dependsOnKeys:null
- disabled:false
- editablePrefill:false
- helperText:null
- label:"Qty"
- labelAction:null
- name:"qty"
- placeholder:null
- prefillRefreshOn:null
- prefillResetOn:null
- prefix:null
- prefixFieldName:null
- readOnly:false
- required:false
- suffix:null
- suffixFieldName:null
- tabIndex:null
- tooltip:null
- type:null
- value:null
RowAction::duplicate() and RowAction::remove() are the built-ins; chain ->label(), ->icon(), or
->danger() 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 are registered per row — items.{index}.field — 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'), ]);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.