Skip to content

Proposal: a Repeater field (repeating groups), implemented in javaabu/form-builder #18

Open

Description

@n4ff4h

Not blocking: javaabu/form-builder ships the field itself. This issue proposes moving it into stencil once the API settles, so other packages can use it.

stencil has no repeater, and form-builder needs repeating groups. So form-builder implements one as a stencil Field: Javaabu\FormBuilder\Stencil\Repeater (source). It's tested with both drivers.

Repeater::make('references')
    ->schema(fn (string $row) => [            // $row is the row's state path: references.0
        TextInput::make('name')->required(),
        Select::make('relationship')->options([...]),
        TextInput::make('other')->visibleWhen("{$row}.relationship", 'other'),
    ])
    ->minRows(1)->maxRows(3)->addLabel(__('Add a reference'))->rowLabel(__('Reference :number'));

How it works

  • State and rows. The state is a list of rows. Each row is a Group with statePath('{key}') under the repeater, so names come out as references[0][name] and rules as references.0.name. The array schema is deep-copied per row, or a closure is called with the row's path.

  • Validation and dehydration. The rows' fields aren't in Form::getFields(), because how many there are depends on the state, and getFields() is cached before fill(). Repeater::getFlatFields() returns []. The repeater merges its rows' rules, attributes (with the row label, e.g. "Name (Reference 2)") and messages, and dehydrates its rows itself. Conditions use absolute paths, so isHiddenByConditions and isDisabledByConditions work per row.

  • Finding fields. EntryForm::getField() (form-builder's Form subclass) also finds row fields by full path, so condition selectors resolve inside rows. Moving this into Form::getField() would make it work for any form.

  • Rendering. The node's props carry:

    • minRows, maxRows, addLabel, removeLabel, rowLabel (with :number)
    • rowKeys and nextRow
    • rowPlaceholder (__ROW__)
    • template: a JSON node of an empty row, with __ROW__ in names, ids and selectors

    The Blade view renders the rows plus a <template> row, and a small script copies it with the next row number. The React component (FormBuilderRepeater) does the same with rowFromTemplate().

What upstreaming would need

  1. Repeater in Javaabu\Stencil\Fields, a repeater Blade view, and a React component in builtInComponents.
  2. Optionally, Form::getField() resolving row fields, and Form::getFields() exposing them once the state is known.
  3. The template and placeholder documented in the JSON format (docs/advanced-usage/json-format.md).

Once stencil has it, form-builder would switch to it and keep a class alias.

Activity

  1. added
    next-genNext-gen Javaabu packages
    cross-packageRequested by or affecting another next-gen package
    on Nov 5, 2026
  2. n4ff4h commented on Nov 6, 2026

    @n4ff4h
    CollaboratorAuthor

    Orchestrator note: deferring this to after v1.0. form-builder ships its own repeater, so nothing is blocked; moving it into stencil is a refactor for a later minor release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    cross-packageRequested by or affecting another next-gen packagenext-genNext-gen Javaabu packages

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions