DEMO / LiveComponent

Embedded CollectionType Form

Unlock the potential of Symfony's CollectionType while writing zero JavaScript.
This demo shows off adding and removing items entirely in PHP & Twig.

Item Priority
// ... use statements hidden - click to show
use App\Entity\TodoList;
use App\Form\TodoListFormType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\DefaultActionTrait;
use Symfony\UX\LiveComponent\LiveCollectionTrait;

#[AsLiveComponent]
class TodoListForm extends AbstractController
{
    use DefaultActionTrait;
    use LiveCollectionTrait;

    #[LiveProp(fieldName: 'formData')]
    public ?TodoList $todoList;

    protected function instantiateForm(): FormInterface
    {
        return $this->createForm(
            TodoListFormType::class,
            $this->todoList
        );
    }
}
<div
    {{ attributes }}
>
    {{ form_start(form) }}
        <div class="row">
            <div class="col-4">
                {{ form_row(form.name, {
                    label: false,
                    attr: {
                        placeholder: 'Give your list a name'
                    }
                }) }}
            </div>
        </div>

        <table class="table table-borderless form-no-mb">
            <thead>
                <tr>
                    <td>Item</td>
                    <td>Priority</td>
                </tr>
            </thead>
            <tbody>
                {% for key, itemForm in form.todoItems %}
                    <tr>
                        <td>
                            {{ form_row(itemForm.description, {
                                label: false,
                                row_attr: {class: 'mb-1'},
                                attr: {
                                    placeholder: 'Walk the pygmy hippo'
                                }
                            }) }}
                        </td>
                        <td>
                            {{ form_row(itemForm.priority, {
                                row_attr: {class: ''},
                                label: false,
                            }) }}
                        </td>
                        <td>
                            {{ form_row(itemForm.vars.button_delete, {label: 'X', attr: {class: 'btn btn-outline-danger'}}) }}
                        </td>
                    </tr>
                {% endfor %}
            </tbody>
        </table>

        {{ form_widget(form.todoItems.vars.button_add, {label: '+ Add Item', attr: {class: 'btn btn-outline-primary'}}) }}

        <button type="submit" class="btn btn-success" formnovalidate>Save</button>
    {{ form_end(form) }}
</div>