Laravel Livewire Form Submission Example

In this tutorial, we are going to create a simple registration form using Laravel. But we are not going to use the default validation method for our form.

We are going to use Livewire with Laravel. Livewire is a full-stack framework for Laravel that makes building a dynamic interface simple, without leaving the Laravel.

Registration Form

Table of content

Setup Laravel

Laravel has various ways to install your application. We are going to use the old method i.e. composer to setup the Laravel application.

composer create-project laravel/laravel form-app

Let finish the installation then navigate the form-app directory and run the serve command to start your application.

cd form-app
php artisan serve

Install Livewire Package

As we already discussed to handle the registration form with Livewire, so let’s install the Livewire package and setup it for our Laravel application.

composer require livewire/livewire

We requires to add the livewire blade directives, that helps to inject the style and JavaScript to every page. Add them to header and footer so both directives available for whole application.

...
    @livewireStyles
</head>
<body>
    ...

    @livewireScripts
</body>
</html>

Create Registration Component with Livewire

Let’s jump to the next part of our application i.e. creating our first component.

php artisan make:livewire Registration

This command will create a component class under app/Http/Livewire directory and blade template under resources/views/livewire directory.

Let’s open the Registration.php file under app/Http/Livewire directory and start adding the form properties.

<?php

namespace App\Http\Livewire;

use Livewire\Component;

class Registration extends Component
{

    public $firstName;

    public $lastName;

    public $email;

    public $address;

    public $city;

    public $state;

    public $zip;

    public function submit() {

        $validatedData = $this->validate();
    }

    public function render()
    {
        return view('livewire.registration');
    }
}

The above component has the following properties i.e. First Name, Last Name, Email, Address, City, State and Zip code. All the properties has been defined in the component.

Now let’s move to the registration.blade.php template and assign these properties and the submit method to the form.

<div class="max-w-6xl mx-auto sm:px-6 lg:px-8">
    <div class="flex justify-center pt-8 sm:pt-0">
        <h1 class="text-3xl font-semibold">Registration Form</h1>
    </div>

    <div class="mt-8 bg-white dark:bg-gray-800 overflow-hidden shadow sm:rounded-lg">
        <div class="grid grid-cols-4">
            <div class="col-start-2 col-span-2 p-6">
                <form wire:submit.prevent="submit" method="POST">

                    <div class="shadow overflow-hidden sm:rounded-md">
                        <div class="px-4 py-5 bg-white sm:p-6">
                        <div class="grid grid-cols-6 gap-6">
                            <div class="col-span-6 sm:col-span-3">
                                <label for="firstName" class="block text-sm font-medium text-gray-700">First name</label>
                                <input type="text" wire:model="firstName" id="firstName" autocomplete="given-name" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md">
                            </div>

                            <div class="col-span-6 sm:col-span-3">
                                <label for="last_name" class="block text-sm font-medium text-gray-700">Last name</label>
                                <input type="text" wire:model="lastName" id="last_name" autocomplete="family-name" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md">
                            </div>

                            <div class="col-span-6">
                                <label for="email" class="block text-sm font-medium text-gray-700">Email address</label>
                                <input type="text" wire:model="email" id="email" autocomplete="email" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md">
                            </div>



                            <div class="col-span-6">
                                <label for="address" class="block text-sm font-medium text-gray-700">Street address</label>
                                <input type="text" wire:model="address" id="address" autocomplete="address" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md">
                            </div>

                            <div class="col-span-6 sm:col-span-6 lg:col-span-2">
                                <label for="city" class="block text-sm font-medium text-gray-700">City</label>
                                <input type="text" wire:model="city" id="city" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md">
                            </div>

                            <div class="col-span-6 sm:col-span-3 lg:col-span-2">
                                <label for="state" class="block text-sm font-medium text-gray-700">State / Province</label>
                                <input type="text" wire:model="state" id="state" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md">
                            </div>

                            <div class="col-span-6 sm:col-span-3 lg:col-span-2">
                                <label for="zip" class="block text-sm font-medium text-gray-700">ZIP / Postal</label>
                                <input type="text" wire:model="zip" id="zip" autocomplete="zip" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md">
                            </div>
                        </div>
                        </div>
                        <div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
                            <button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
                                Submit
                            </button>
                        </div>
                    </div>

                </form>

            </div>

        </div>
    </div>

</div>

We have bound the submit method with wire:submit.prevent like the below code.

<form wire:submit.prevent="submit" method="POST">
    ....
    ....
</form>

And the defined properties has been bound with wire:model.

<div class="col-span-6 sm:col-span-3">
    <label for="firstName" ...>First name</label>
    <input type="text" wire:model="firstName" id="firstName" ...>
</div>

<div class="col-span-6 sm:col-span-3">
    <label for="last_name" ...>Last name</label>
    <input type="text" wire:model="lastName" id="last_name" ...>
</div>

Realtime Validation Error with Livewire

We have added the codes to the component class and the blade file. But haven’t added the error messages yet. It’s pretty easy to add the validation error with Livewire. Open the registration.blade.php file and add the following directive to display the error.

<div class="col-span-6 sm:col-span-3">
    <label for="firstName" ...>First name</label>
    <input type="text" wire:model="firstName" id="firstName" ...>
    @error('firstName') <span ...>{{ $message }}</span> @enderror
</div>

<div class="col-span-6 sm:col-span-3">
    <label for="last_name" ...>Last name</label>
    <input type="text" wire:model="lastName" id="last_name" ...>
    @error('lastName') <span ...>{{ $message }}</span> @enderror
</div>

Now open the Registration.php class and the validation rules and method to display the realtime error.

<?php

namespace App\Http\Livewire;

use Livewire\Component;

class Registration extends Component
{

    public $firstName;

    public $lastName;

    public $email;

    public $address;

    public $city;

    public $state;

    public $zip;

    protected $rules = [
        'firstName' => 'required|max:20',
        'lastName' => 'required|max:20',
        'email' => 'required|email',
        'address' => 'required|max:100',
        'city' => 'required',
        'state' => 'required',
        'zip' => 'required',
    ];

    public function updated($propertyName) {

        $this->validateOnly($propertyName);
    }

    public function submit() {

        $validatedData = $this->validate();

        // Add registration data to modal
        dd( $validatedData );
    }

    public function render()
    {
        return view('livewire.registration');
    }
}

The updated() method helps to set the realtime validation.

Render Livewire Component to Laravel View

Now our registration component is complete and it’s time to render it to the desired view. The most common way to render the Livewire component to any page by using the <livewire: tag with the component name.

<livewire:registration />

Now open the terminal the run your Laravel application.

php artisan serve
Livewire Validation Error

We hope this article will help you to implement form validation using livewire in your Laravel application. If you like this article then please follow us on Facebook and Twitter.