How to dynamically add input fields with livewire

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

How to Dynamically Add Input Fields with Livewire: Solving the Dynamic Data Challenge

As a senior developer working with modern full-stack frameworks, one of the most common challenges in building interactive interfaces is managing dynamic data updates without writing extensive, complex JavaScript. Livewire excels at bridging the gap between server-side logic (PHP) and front-end interactivity, making dynamic form management remarkably straightforward.

If you are trying to dynamically add new input fields when a button is clicked, and you encounter errors like get_class(): Argument #1 ($object) must be of type object, string given, it usually points to an issue in how the component's state is initialized or how methods interact with properties within the Livewire lifecycle.

This post will diagnose the likely cause of your error and provide a robust, corrected pattern for dynamically adding elements in a Livewire component. We will walk through the correct structure, ensuring your dynamic additions work seamlessly.


Diagnosing the Error: State Management is Key

The error you encountered (get_class(): Argument #1 ($object) must be of type object, string given) strongly suggests that somewhere in your component's lifecycle (likely mount() or an initial property assignment), a function expected a proper object reference but received a string instead. In the context of Livewire and PHP components, this often happens when dealing with Eloquent collections or poorly initialized properties.

The core principle in Livewire is that all mutable state must be managed within the component class and updated via public properties. You don't need complex manual DOM manipulation; you just need to tell Livewire what data to render based on your PHP properties.

Let’s fix the provided example by ensuring proper array handling for dynamic additions.

The Correct Approach: Dynamic Array Manipulation in Livewire

To dynamically add input fields, we must manage a collection (an array) of items within our component class. When the "Add More" button is clicked, the method should push a new value into that array, and Livewire will automatically re-render the view with the updated list.

1. Corrected Livewire Component Class

We need to ensure that $tests is initialized as an empty array ([]) so we can safely use array push operations in our methods. We will remove the confusing mount() logic for this simple example, focusing purely on dynamic addition.

<?php

namespace App\Http\Livewire;

use Livewire\Component;

class TestManager extends Component
{
    // Initialize $tests as an empty array to hold our dynamic inputs
    public $tests = [];

    public function render()
    {
        return view('livewire.test-manager'); // Adjust view path as needed
    }

    /**
     * Method to dynamically add a new, empty input field.
     */
    public function addTestField()
    {
        // Dynamically add a new empty string element to the array
        $this->tests[] = '';
    }
}

2. Corrected Blade View Implementation

The view now simply iterates over the $tests property. Crucially, we use the index provided by the loop to bind each input field uniquely using wire:model. This ensures that when you add a new item, Livewire knows exactly which input field corresponds to which data point.

<div>
    <form wire:submit.prevent="save">
        @foreach($tests as $index => $test)
            <div>
                <label for="title{{$index}}">Title #{{$index}}</label>
                {{-- Use the index to bind the model dynamically --}}
                <input 
                    wire:model="tests.{{$index}}" 
                    type="text"
                >
            </div>
        @endforeach
        <button type="submit">Save All</button>
    </form>
    
    {{-- The button that triggers the dynamic addition --}}
    <button wire:click="addTestField">ADD MORE INPUTS</button>
</div>

Explanation of Best Practices

  1. State as an Array: By defining $tests = [], we establish a clear, mutable state within the component. This array is the source of truth for what is displayed on the screen.
  2. Direct Manipulation: The addTestField() method uses $this->tests[] = '';. This is the standard, efficient way to push new data into a PHP array in Livewire. Livewire detects this change and automatically updates the DOM.
  3. Dynamic Binding (wire:model): Notice how we use wire:model="tests.{{$index}}". Instead of binding to a single property, we are binding to an index within the array. This is vital for dynamic lists. When you iterate through the loop, Livewire binds each input field directly to its corresponding element in the $tests array, allowing seamless two-way data flow.

Conclusion

Dynamically adding elements in Livewire hinges entirely on managing your component's state as structured arrays and using methods to modify those arrays. By focusing on clean array manipulation within your PHP class and leveraging wire:model with indexed properties in your Blade view, you can create highly responsive and interactive forms without writing complex frontend JavaScript.

For more advanced state management patterns and deeper dives into Laravel component architecture, always refer to the official documentation at https://laravelcompany.com. Happy coding!