In this section, we will see a loading circle animation after submitting a form in Laravel Livewire. To achieve this, we will utilize Livewire Loading States. The wire:loading
directive is particularly useful, as it is only visible while waiting for a network action to complete.
Use sleep() function in livewire component
The sleep() function delays execution of the current script for a specified number of seconds.
Livewire Component File
<?php
namespace App\Http\Livewire;
use App\Models\Post;
use Livewire\Component;
use Livewire\WithPagination;
class PostForm extends Component
{
use WithPagination;
public $title;
public $description;
public $post_id;
protected $rules = [
'title' => 'required',
'description' => 'required',
];
public function storePost()
{
$this->validate();
$post = Post::create([
'title' => $this->title,
'description' => $this->description
]);
// delay
sleep(3);
$this->reset();
session()->flash('message', 'Post created successfully.');
}
public function render()
{
return view('livewire.post-form', ['posts' => Post::latest()->paginate(10)]);
}
}
Livewire Component View File
You can use wire:loading
alone or in combination with wire:target
. I suggest using wire:loading
with wire:target
as it makes the code more readable.
Loading Button ui
<span class="inline-flex rounded-md shadow-sm">
<button type="submit" class="inline-flex items-center px-4 py-2 text-base font-medium leading-6 text-white transition duration-150 ease-in-out bg-blue-600 border border-transparent rounded-md hover:bg-blue-500 focus:border-blue-700 active:bg-blue-700">
<svg wire:loading class="w-5 h-5 mr-3 -ml-1 text-white animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Submit
</button>
</span>
resources/views/livewire/your-component.blade.php
<div>
<h4 class="mb-4 text-2xl font-bold">Post</h4>
@if (session()->has('message'))
<div class="px-4 py-4 text-white text-green-800 bg-green-200 border-l-4 border-green-900 rounded">
{{ session('message') }}
</div>
@endif
<div>
<div class="container mx-auto">
<form method="POST" wire:submit.prevent="storePost">
@csrf
<div>
<label for="title">Title</label>
<input type="text" wire:model.lazy="title" class="w-full py-2 rounded" />
@error('title')
<span class="text-red-600">{{ $message }}</span>
@enderror
</div>
<div class="mt-8">
<label class="block mb-2 text-xl">Description </label>
<textarea wire:model.lazy="description" rows="3" cols="20" class="w-full rounded">
</textarea>
@error('description')
<span class="text-red-600">{{ $message }}</span>
@enderror
</div>
<div class="flex">
<span class="inline-flex rounded-md shadow-sm">
<button type="submit"
class="inline-flex items-center px-4 py-2 text-base font-medium leading-6 text-white transition duration-150 ease-in-out bg-blue-600 border border-transparent rounded-md hover:bg-blue-500 focus:border-blue-700 active:bg-blue-700">
<svg wire:loading wire:target="storePost" class="w-5 h-5 mr-3 -ml-1 text-white animate-spin"
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor"
stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
</path>
</svg>
Submit
</button>
</span>
</div>
</form>
</div>
</div>
</div>
If you want to show loading indicators only for specific actions.
<div>
<button wire:click="activeUser">Show</button>
<div wire:loading wire:target="activeUser">
Processing ...
</div>
</div>
Delaying loading indicator
You can customize the delay duration with the following modifier.
<div wire:loading.delay.shortest>...</div> <!-- 50ms -->
<div wire:loading.delay.shorter>...</div> <!-- 100ms -->
<div wire:loading.delay.short>...</div> <!-- 150ms -->
<div wire:loading.delay>...</div> <!-- 200ms -->
<div wire:loading.delay.long>...</div> <!-- 300ms -->
<div wire:loading.delay.longer>...</div> <!-- 500ms -->
<div wire:loading.delay.longest>...</div> <!-- 1000ms -->