Laravel Livewire CRUD Application with JetStream and Tailwindcss

This tutorial will explain how to create simple CRUD operation in Laravel 8 using Livewire and Jetstream packages. In this project we will build a simple blog which displays posts. So lets begin…

Laravel Jetstream

Laravel Jetstream is starter kit for Laravel ecosystem which provides an elegant login, registration, email verification, two-factor authentication, session management, API via Laravel Sanctum and optional team management features.


Livewire is a full-stack framework for Laravel based applications which helps to create dynamic interfaces simple, without leaving the comfort of Laravel.


Tailwindcss is utility CSS framework that helps to build modern websites without ever leaving your HTML. Tailwindcss will come by default when you install Laravel application.

With the help of all these powerful technologies, we will show how to add a database to your project and do all CRUD stuffs using the application. In addition, we will also show basic server-side validation when we store the data into the MySQL database.

Steps include in this Project

  • Step 1: Initial set up, Install Livewire and Jetstream
  • Step 2: Database Configuration
  • Step 3: Model Migration
  • Step 4: Create Livewire Components
  • Step 5: Prepare Blade View
  • Step 6: Create Routes
  • Step 7: Start Development Server

Initial Set Up, Install Livewire and Jetstream

Let’s install Laravel fresh application using terminal. You can use any name. We are using laravel-jetstream-blog.

composer create-project --prefer-dist laravel/laravel-jetstream-blog

Now change the directory into newly created project then install Laravel jetstream.

cd laravel-jetstream-blog

composer require laravel/jetstream

php artisan jetstream:install livewire

At this point you will achieve Laravel user authentication part with the help of Jetstream. You will see Login and Register button in your app.

Now install nmp packeges and compile all the assets. Use both the npm commands as follow.

npm install && npm run dev

Database Configuration

Next, we connect our app to the database. To connect with database we need to make some configuration on the .env file.

You can use any name for DB_DATABASE, DB_USERNAME and DB_PASSWORD. Remember to change DB_HOST and DB_PORT if you are using Docker for this project (Refer docker tutorials).


Model Migration

It is time to create our first model. To create a model we can simply use terminal and execute the following command. Here we are creating Post model. You can give any name for the model.

php artisan make:model Posts -m

In the Post model, we will add table values such as title, body and the slug in the $fillable array.

<?phpnamespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Posts extends Model
    use HasFactory;

    protected $fillable = [


Next, make our first migration to the database. When we run the migration command, new migration will be placed in your database/migrations directory. We can use any name for migration. Each migration filename contains a timestamp that allows Laravel to determine the order of the migrations:

php artisan make:migration create_posts_table

Then configure the migration table for Post, so add the table properties in the database/migrations/create_post_table.php file.


use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostTable extends Migration
     * Run the migrations.
     * @return void
    public function up()
        Schema::create('posts', function (Blueprint $table) {
            $table->string('title', 100);

     * Reverse the migrations.
     * @return void
    public function down()

Create Livewire Components

At this point we can create our first Livewire components. To create our files we run this command. It will generated two files, one in Http and another in resources directories.

php artisan make:livewire post

livewire class: app/Http/Livewire/Post.php

Blade view: resources/views/livewire/post.blade.php

Now open Post class in the Livewire folder and define the post methods. Basically we will have all CRUD operations such create, update and delete posts in this file.


namespace App\Http\Livewire;

use Livewire\Component;

use App\Models\Posts;

class Post extends Component


public $posts, $title, $body, $slug;

public $isModalOpen = 0;

public function render()



return view('');


public function create(){




public function openModalPopover()


$this->isModalOpen = true;


public function closeModalPopover()


$this->isModalOpen = false;


public function resetForm(){





public function store(){


'title' => 'required',

'body' => 'requuired',

'slug' => 'required',





'title'  => $this->title,

'body'   => $this->body,

'slug'   => $this->slug,


session()->flash('message', $this->post_id ? 'Post updated' : 'Post created');




public function edit($id) {

$post = Post::findOrFail($id);

$this->id = $id;

$this->title = $post->title;

$this->body = $post->body;

$this->slug = $post->slug;



public function delete($id){


session()->flash('message', 'Message deleted Successfully');



Prepare Blade View

Now let’s open post blade file, so that we can display all the data in the UI.

It will show data in tabular forms where users can take actions to update or edit post data.

To achieve that, simply insert the following code in resources/views/livewire/post.blade.php file.

<x-slot name="header">
<h2 class="text-center">Laravel 8 Livewire Blog Demo</h2>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg px-4 py-4">
@if (session()->has('message'))
<div class="bg-teal-100 border-t-4 border-teal-500 rounded-b text-teal-900 px-4 py-3 shadow-md my-3"
<div class="flex">
<p class="text-sm">{{ session('message') }}</p>
<button wire:click="create()"
class="bg-green-700 text-white font-bold py-2 px-4 rounded my-3">Create Student</button>
<table class="table-fixed w-full">
<tr class="bg-gray-100">
<th class="px-4 py-2 w-20">No.</th>
<th class="px-4 py-2">Title</th>
<th class="px-4 py-2">Body</th>
<th class="px-4 py-2">Slug</th>
<th class="px-4 py-2">Action</th>
@foreach($posts as $post)
<td class="border px-4 py-2">{{ $post->id }}</td>
<td class="border px-4 py-2">{{ $post->title }}</td>
<td class="border px-4 py-2">{{ $post->body}}</td>
<td class="border px-4 py-2">{{ $post->slug}}</td>
<td class="border px-4 py-2">
<button wire:click="edit({{ $post->id }})"
class="bg-blue-500  text-white font-bold py-2 px-4 rounded">Edit</button>
<button wire:click="delete({{ $student->id }})"
class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">Delete</button>

Lastly create a new file named create.blade.php file inside the resources/views/livewire/ then add the below code in that file.

<div class="fixed z-10 inset-0 overflow-y-auto ease-out duration-400">
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen"></span>?
    <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
        role="dialog" aria-modal="true" aria-labelledby="modal-headline">
            <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
                <div class="">
                    <div class="mb-4">
                        <label for="exampleFormControlInput1"
                            class="block text-gray-700 text-sm font-bold mb-2">Name</label>
                        <input type="text"
                            class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
                            id="exampleFormControlInput1" placeholder="Enter Name" wire:model="name">
                        @error('name') <span class="text-red-500">{{ $message }}</span>@enderror
                    <div class="mb-4">
                        <label for="exampleFormControlInput2"
                            class="block text-gray-700 text-sm font-bold mb-2">Email:</label>
                            class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
                            id="exampleFormControlInput2" wire:model="email"
                            placeholder="Enter Email"></textarea>
                        @error('email') <span class="text-red-500">{{ $message }}</span>@enderror
                    <div class="mb-4">
                        <label for="exampleFormControlInput2"
                            class="block text-gray-700 text-sm font-bold mb-2">Mobile:</label>
                            class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
                            id="exampleFormControlInput2" wire:model="mobile"
                            placeholder="Enter Mobile"></textarea>
                        @error('mobile') <span class="text-red-500">{{ $message }}</span>@enderror
            <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
                <span class="flex w-full rounded-md shadow-sm sm:ml-3 sm:w-auto">
                    <button wire:click.prevent="store()" type="button"
                        class="inline-flex justify-center w-full rounded-md border border-transparent px-4 py-2 bg-red-600 text-base leading-6 font-bold text-white shadow-sm hover:bg-red-700 focus:outline-none focus:border-green-700 focus:shadow-outline-green transition ease-in-out duration-150 sm:text-sm sm:leading-5">
                <span class="mt-3 flex w-full rounded-md shadow-sm sm:mt-0 sm:w-auto">
                    <button wire:click="closeModalPopover()" type="button"
                        class="inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-base leading-6 font-bold text-gray-700 shadow-sm hover:text-gray-700 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue transition ease-in-out duration-150 sm:text-sm sm:leading-5">

Create Routes

Now it is time to create our first route. It enables navigation for the Livewire app. Remember to import all Livewire classes. In this case Post class and define the route method. To do so, open resources/web.php file.


use Illuminate\Support\Facades\Route;
use App\Http\Livewire\Post;

Route::get('posts', Post::class);

Start Development Server

Now run the development server. So, use php artisan command along with the serve tag to invoke the Laravel development server.

php artisan serve

You can test the app by using the given url on the browser’s address bar.

Thats all!