Skip to main content

Black Friday 2025! Only until December 1st: coupon FRIDAY25 for 40% off Yearly/Lifetime membership!

Read more here
Premium Members Only
Join to unlock this tutorial and all of our courses.
Tutorial Premium Tutorial

Livewire 3 CRUD with Form Objects and Modal Wire Elements

September 11, 2023
10 min read

Livewire v3 introduced Form Objects to offload the field logic from the Component. In this tutorial, we'll build the create/edit modal forms powered by the Wire Elements package and reuse the same Livewire component and Form Object.

modal with unique rule


Preparation: Laravel Project

For the Laravel project visual design, we will use our own starter kit Laravel Breeze Pages Skeleton.

In the Model Product we will have two DB fields: name and description.

database/migrations/xxx_create_products_table.php:

public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description');
$table->timestamps();
});
}

app/Models/Product.php:

class Product extends Model
{
protected $fillable = [
'name',
'description',
];
}

Install Livewire and Customize Breeze

First, of course, we need to install install Livewire.

composer require livewire/livewire

Next, because Alpine.js is baked into the core of Livewire, we need to remove it from our Breeze-powered skeleton. If you don't use Laravel Breeze, you can skip this step.

resources/js/app.js:

import './bootstrap';
 
import Alpine from 'alpinejs';
 
window.Alpine = Alpine;
 
Alpine.start();

And recompile assets.

npm run prod

The last thing is changing the main layout path.

Livewire looks for a layout in resources/views/components/layouts/app.blade.php, but our Breeze-based Starter kit has it in a different place, so we need to set it in the Livewire config.

php artisan livewire:publish --config

config/livewire.php:

return [
// ...
'layout' => 'components.layouts.app',
'layout' => 'layouts.app',
// ...
];

And that's it, we can use Livewire in our project. Now, let's create a Livewire component to show the products list.


Livewire Component: Products List

php artisan make:livewire ProductList

app/Livewire/ProductList.php:

use App\Models\Product;
use Illuminate\Contracts\View\View;
 
class ProductList extends Component
{
public function render(): View
{
return view('livewire.product-list', [
'products' => Product::all(),
]);
}
}

Let's add a link to the navigation and show the products table.

resources/views/layouts/navigation.blade.php:

// ...
 
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
<x-nav-link :href="route('users.index')" :active="request()->routeIs('users.index')">
{{ __('Users') }}
</x-nav-link>
<x-nav-link :href="route('products')" :active="request()->routeIs('products')">
{{ __('Products') }}
</x-nav-link>
</div>
 
// ...

resources/views/livewire/product-list.blade.php:

<div>
<x-slot name="header">
<h2 class="text-xl font-semibold leading-tight text-gray-800">
{{ __('Products') }}
</h2>
</x-slot>
 
<div class="py-12">
<div class="mx-auto max-w-7xl sm:px-6 lg:px-8">
<div class="overflow-hidden bg-white shadow-sm sm:rounded-lg">
<div class="p-6 overflow-hidden overflow-x-auto bg-white border-b border-gray-200">
 
<div class="min-w-full align-middle">
<table class="min-w-full border divide-y divide-gray-200">
<thead>
<tr>
<th class="px-6 py-3 text-left bg-gray-50">
<span class="text-xs font-medium leading-4 tracking-wider text-gray-500 uppercase">Name</span>
</th>
<th class="px-6 py-3 text-left bg-gray-50">
<span class="text-xs font-medium leading-4 tracking-wider text-gray-500 uppercase">Description</span>
</th>
<th class="px-6 py-3 text-left bg-gray-50">
</th>
</tr>
</thead>
 
<tbody class="bg-white divide-y divide-gray-200 divide-solid">
@forelse($products as $product)
<tr class="bg-white">
<td class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap">
{{ $product->name }}
</td>
<td class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap">
{{ $product->description }}
</td>
<td class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap">
{{-- Edit Button --}}
</td>
</tr>
@empty
<tr class="bg-white">
<td colspan="3" class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap">
No products found.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
 
</div>
</div>
</div>
</div>
</div>

products table


Modal with Form Object

Now, let's create a component that will be a modal and...

Premium Members Only

This advanced tutorial is available exclusively to Laravel Daily Premium members.

Premium membership includes:

Access to all premium tutorials
Video and Text Courses
Private Discord Channel

Comments & Discussion

RB
Rajesh Budhathoki ✓ Link copied!

The Git repo link is not working!

A
adithyaricky ✓ Link copied!

maybe mr pivolas forget to make it public. this repo are similar https://github.com/LaravelDaily/Livewire-3-Course-Demo

N
Nerijus ✓ Link copied!

@adithyaricky your mentioned is public

RB
Rajesh Budhathoki ✓ Link copied!

Link is still not fixed.

https://github.com/LaravelDaily/Livewire-3-CRUD-Modal-Unique-Demo

RB
Rajesh Budhathoki ✓ Link copied!

I've identified errors in the tutorial, and my code isn't functioning correctly. I'd like to access the source code. Could you please correct the link as soon as possible?

N
Nerijus ✓ Link copied!

Will be fixed today

N
Nerijus ✓ Link copied!

Now it's public

M
Masstech ✓ Link copied!

i don't see the link for the video. Do you have video tutorial of this topic ?

N
Nerijus ✓ Link copied!

Povilas have plenty videos on YouTube about livewire

RB
Rajesh Budhathoki ✓ Link copied!

Dear Povilas, I noticed an issue in your code within the app/Livewire/ProductModal.php file. It appears that there is an incorrect view being used inside the render() method. Similarly, there seems to be a filename discrepancy in resources/views/livewire/product-form.blade.php, possibly causing issues.

I cloned your code and tested the application, but it doesn't seem to open the modal as expected.

I've had a somewhat frustrating experience with the course "Livewire 3 From Scratch: Practical Course." As a result, I decided to jump into this CRUDy article to fill in the gaps in my understanding of Livewire. However, I found myself facing similar challenges with this article as well. I'm hoping there's a beginner-friendly CRUDy course available for Livewire v3 that can help me grasp the concepts more effectively. Thank you for your assistance!

T
Thakchand ✓ Link copied!

Add

@livewire('wire-elements-modal')

inside the body section of resources/views/layouts/app.blade.php

T
Thakchand ✓ Link copied!

resources/views/livewire/product-form.blade.php

should be kept as

resources/views/livewire/product-modal.blade.php

BM
Bradley Miller ✓ Link copied!

Can you show the navigation link when collapsed code also? The demo is fine on a computer but I have no links when on mobile?

N
Nerijus ✓ Link copied!

You need to add them in the navigation.blade.php

BM
Bradley Miller ✓ Link copied!

The example shows the navigation but it didn't put it into the drop-link area.

N
Nerijus ✓ Link copied!

Yes because we aren't building a full app. It's just to show a concept how to do something. If you need to links for mobile feel free to do that it's in the same

RP
Rogerio Picilli ✓ Link copied!

It appears that this step-by-step guide is missing some information. I'm not sure if it's intentional to encourage research and learning, or if it's simply an oversight. First, what are the routes? Are we using Controllers to call the Livewire pages/components, or are we calling them directly without the use of controllers? How are Data Models being passed to the view?

I am a subscriber to this website, but sometimes I struggle to make the examples work."

N
Nerijus ✓ Link copied!

For this tutorial no contdollera are used this is a full page component. For data the route model binding is being used. Also the source code is available you can check

T
Thakchand ✓ Link copied!

define route in web.php as Route::get('/products', ProductList::class)->name('products');

RA
Richard A. Hoyle ✓ Link copied!

Can you please Redo this Tutorial using the 2.0.7 version of LivewireUI\Modal\ModalComponent I just can not get this Tutorial to work It is to outdated. not even your Github Repository will work for me.

N
Nerijus ✓ Link copied!

This is a new tutorial only a month old and uses the 2.o.7 version of wire-elements/modal.

ZF
Zoltan Farkas ✓ Link copied!

Hy! I would like to replace the listing section in the description with the Livewire PowerGrid listing. Is there a description available regarding this? Thank you.

N
Nerijus ✓ Link copied!

No, we don't have any tutorials using powergrid. Maybe Povilas has a YouTube video. Just check their docs

ZF
Zoltan Farkas ✓ Link copied!

Okay, thank you.

ZF
Zoltan Farkas ✓ Link copied!

Will there be a solution for the delete function in the near future?

N
Nerijus ✓ Link copied!

What do you need about it? Create a delete method and pass id to it. In that method delete. There are a couple livewire courses that do this.

DS
Dmytro Sakharuk ✓ Link copied!

Then in the title of the article in the CRUD acronym you need to remove the letter D :)

JL
Joshua Lictan ✓ Link copied!

How to adjust the width or size of the modal

<div class="overflow-x-auto">
    <table class="min-w-full bg-white divide-y divide-gray-200">
        <thead>
        <tr>
            <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                Category
            </th>
            <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                Total
            </th>
            <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                Reserved
            </th>
            <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                Available
            </th>
        </tr>
        </thead>
        <tbody class="bg-white divide-y divide-gray-200">
        <!-- Example row (repeat for each item) -->
        <tr>
            <td class="px-6 py-4 whitespace-nowrap">
                <!-- Category value -->
            </td>
            <td class="px-6 py-4 whitespace-nowrap">
                <!-- Total value -->
            </td>
            <td class="px-6 py-4 whitespace-nowrap">
                <!-- Reserved value -->
            </td>
            <td class="px-6 py-4 whitespace-nowrap">
                <!-- Available value -->
            </td>
        </tr>
        <!-- Add more rows as needed... -->
        </tbody>
    </table>
</div>

i have design here that table is horizontally scrollable how to make it reponsive

N
Nerijus ✓ Link copied!

For modal refer to the docs of the package. For table you will need to learn CSS.

JL
Joshua Lictan ✓ Link copied!

no matter what i do to my modal it will not change its width, do i need the pro version?

i already did public static function modalMaxWidth(): string { return '2xl'; }

M
Modestas ✓ Link copied!

Did you compile your assets after changin the width?

Keep in mind: With any css changes you need to run npm run build to compile them into "available" assets, otherwise - no class will be added.

N
Nerijus ✓ Link copied!

Just adding a method like that shouldn't change the width if tailwind doesn't compile that class. Check the docs this part https://github.com/wire-elements/modal#building-tailwind-css-for-production

JL
Joshua Lictan ✓ Link copied!

fixed it, the problem is the minimum width not the maximum

BP
Bruno Pincaro ✓ Link copied!

having the same problem with modal width. how did you solve yours with minimum width ?

N
Nerijus ✓ Link copied!

Refer to package documentation

X
xvlros ✓ Link copied!

Perhaps a general question about Laravel model methods, but how would one verify the $model->update() (or $model->save) / $model->delete() worked and then send that back to the Livewire component for confirmation?

We'd Love Your Feedback

Tell us what you like or what we can improve

Feel free to share anything you like or dislike about this page or the platform in general.