Generate Laravel 11 Tailwind CRUD Operation InnovationM

Generate Laravel 11 Tailwind CRUD Operation

An updated Laravel CRUD Generator version of  ibex/crud-generator now generates CRUD in Tailwind CSS in the blade with the blank Laravel installation.

1- Install Laravel

composer create-project laravel/laravel laravel-11-crud

2- Create Migration

php artisan make:model Posts –migration

For example posts table has the following columns in migration below.

<?php

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

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->string('description');
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};

3- Install ibex/crud-generator

php artisan make:crud posts tailwind

A single command will generate all CRUD operations in a second. This will include a resource PostControllerPost (Model), PostRequest, and all Blade views in Tailwind CSS.

4- Add route in web.php

Route::resource(‘posts’, PostController::class);

Below is the code generated for PostController

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use App\Http\Requests\PostRequest;
use Illuminate\Support\Facades\Redirect;
use Illuminate\View\View;

class PostController extends Controller
{
    public function index(Request $request): View
    {
        $posts = Post::paginate();
        return view('post.index', compact('posts'))
            ->with('i', ($request->input('page', 1) - 1) * $posts->perPage());
    }

public function create(): View
    {
        $post = new Post();
        return view('post.create', compact('post'));
    }

    public function store(PostRequest $request): RedirectResponse
    {
        Post::create($request->validated());
        return Redirect::route('posts.index')
            ->with('success', 'Post created successfully.');
    }
    public function show($id): View
    {
        $post = Post::find($id);
        return view('post.show', compact('post'));
    }
    public function edit($id): View
    {
        $post = Post::find($id);
        return view('post.edit', compact('post'));
    }
    public function update(PostRequest $request, Post $post): RedirectResponse
    {
        $post->update($request->validated());
        return Redirect::route('posts.index')
            ->with('success', 'Post updated successfully');
    }
    public function destroy($id): RedirectResponse
    {
        Post::find($id)->delete();
        return Redirect::route('posts.index')
            ->with('success', 'Post deleted successfully');
    }
}

5- Create view files.

6-Create view file- create.blade.php

<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            {{ __('Create') }} {{modelTitle}}
        </h2>
    </x-slot>
    <div class="py-12">
        <div class="max-w-full mx-auto sm:px-6 lg:px-8 space-y-6">
            <div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
                <div class="w-full">
                    <div class="sm:flex sm:items-center">
                        <div class="sm:flex-auto">
                            <h1 class="text-base font-semibold leading-6 text-gray-900">{{ __('Create') }} {{modelTitle}}</h1>
                            <p class="mt-2 text-sm text-gray-700">Add a new {{ __('{{modelTitle}}') }}.</p>
                        </div>
                        <div class="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
                            <a type="button" href="{{ route('{{modelRoute}}.index') }}" class="block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Back</a>
                        </div>
                    </div>
                    <div class="flow-root">
                        <div class="mt-8 overflow-x-auto">
                            <div class="max-w-xl py-2 align-middle">
                                <form method="POST" action="{{ route('{{modelRoute}}.store') }}"  role="form" enctype="multipart/form-data">
                                    @csrf
                                    @include('{{modelView}}.form')
                                </form>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</x-app-layout>

7- Create view file- edit.blade.php

<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            {{ __('Update') }} {{modelTitle}}
        </h2>
    </x-slot>
    <div class="py-12">
     <div class="max-w-full mx-auto sm:px-6 lg:px-8 space-y-6">
            <div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
                <div class="w-full">
                    <div class="sm:flex sm:items-center">
                        <div class="sm:flex-auto">
                            <h1 class="text-base font-semibold leading-6 text-gray-900">{{ __('Update') }} {{modelTitle}}</h1>
                            <p class="mt-2 text-sm text-gray-700">Update existing {{ __('{{modelTitle}}') }}.</p>
                        </div>
                       <div class="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
                            <a type="button" href="{{ route('{{modelRoute}}.index') }}" class="block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Back</a>
                        </div>
                    </div>
                    <div class="flow-root">
                        <div class="mt-8 overflow-x-auto">
                            <div class="max-w-xl py-2 align-middle">
                                <form method="POST" action="{{ route('{{modelRoute}}.update', ${{modelNameLowerCase}}->id) }}"  role="form" enctype="multipart/form-data">
                                    {{ method_field('PATCH') }}
                                    @csrf
                                    @include('{{modelView}}.form')
                                </form>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</x-app-layout>

 

8-Create view file-  form-field.blade.php

    <div>
        <x-input-label for="{{column_snake}}" :value="__('{{title}}')"/>
        <x-text-input id="{{column_snake}}" name="{{column}}" type="text" class="mt-1 block w-full" :value="old('{{column}}', ${{modelNameLowerCase}}?->{{column}})" autocomplete="{{column}}" placeholder="{{title}}"/>
        <x-input-error class="mt-2" :messages="$errors->get('{{column}}')"/>
    </div>

9-Create view file- form.blade.php

<div class="space-y-6">
    {{form}}
    <div class="flex items-center gap-4">
        <x-primary-button>Submit</x-primary-button>
    </div>
</div>

10-Create view file- index.blade.php

<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            {{ __('{{modelTitlePlural}}') }}
      </h2>
    </x-slot>
    <div class="py-12">
        <div class="max-w-full mx-auto sm:px-6 lg:px-8 space-y-6">
            <div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
                <div class="w-full">
                    <div class="sm:flex sm:items-center">
                        <div class="sm:flex-auto">
                            <h1 class="text-base font-semibold leading-6 text-gray-900">{{ __('{{modelTitlePlural}}') }}</h1>
                            <p class="mt-2 text-sm text-gray-700">A list of all the {{ __('{{modelTitlePlural}}') }}.</p>
                        </div>
                        <div class="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
                           <a type="button" href="{{ route('{{modelRoute}}.create') }}" class="block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Add new</a>
                        </div>
                    </div>
                  <div class="flow-root">
                        <div class="mt-8 overflow-x-auto">
                            <div class="inline-block min-w-full py-2 align-middle">
                                <table class="w-full divide-y divide-gray-300">
                                    <thead>
                                    <tr>
                                        <th scope="col" class="py-3 pl-4 pr-3 text-left text-xs font-semibold uppercase tracking-wide text-gray-500">No</th>
                                       {{tableHeader}}
                                        <th scope="col" class="px-3 py-3 text-left text-xs font-semibold uppercase tracking-wide text-gray-500"></th>
                                    </tr>

                                    </thead>

                                    <tbody class="divide-y divide-gray-200 bg-white">

                                    @foreach (${{modelNamePluralLowerCase}} as ${{modelNameLowerCase}})

                                        <tr class="even:bg-gray-50">

                                            <td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-semibold text-gray-900">{{ ++$i }}</td>

                                            {{tableBody}}

                                            <td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900">

                                                <form action="{{ route('{{modelRoute}}.destroy', ${{modelNameLowerCase}}->id) }}" method="POST">

                                                    <a href="{{ route('{{modelRoute}}.show', ${{modelNameLowerCase}}->id) }}" class="text-gray-600 font-bold hover:text-gray-900 mr-2">{{ __('Show') }}</a>

                                                    <a href="{{ route('{{modelRoute}}.edit', ${{modelNameLowerCase}}->id) }}" class="text-indigo-600 font-bold hover:text-indigo-900  mr-2">{{ __('Edit') }}</a>

                                                    @csrf

                                                    @method('DELETE')

                                                    <a href="{{ route('{{modelRoute}}.destroy', ${{modelNameLowerCase}}->id) }}" class="text-red-600 font-bold hover:text-red-900" onclick="event.preventDefault(); confirm('Are you sure to delete?') ? this.closest('form').submit() : false;">{{ __('Delete') }}</a>

                                                </form>

                                            </td>

                                        </tr>

                                    @endforeach

                                    </tbody>

                                </table>

                                <div class="mt-4 px-4">

                                    {!! ${{modelNamePluralLowerCase}}->withQueryString()->links() !!}
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</x-app-layout>

11- Create view file-  show.blade.php

<x-app-layout>
    <x-slot name="header">
       <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            {{ ${{modelNameLowerCase}}->name ?? __('Show') . " " . __('{{modelTitle}}') }}
        </h2>
    </x-slot>
    <div class="py-12">
        <div class="max-w-full mx-auto sm:px-6 lg:px-8 space-y-6">
            <div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
                <div class="w-full">
                    <div class="sm:flex sm:items-center">
                        <div class="sm:flex-auto">
                            <h1 class="text-base font-semibold leading-6 text-gray-900">{{ __('Show') }} {{modelTitle}}</h1>
                            <p class="mt-2 text-sm text-gray-700">Details of {{ __('{{modelTitle}}') }}.</p>
                        </div>
                        <div class="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">                            <a type="button" href="{{ route('{{modelRoute}}.index') }}" class="block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Back</a>
                        </div>
                    </div>
     <div class="flow-root">
                        <div class="mt-8 overflow-x-auto">
                            <div class="inline-block min-w-full py-2 align-middle">
                                <div class="mt-6 border-t border-gray-100">
                                    <dl class="divide-y divide-gray-100">
                                        {{viewRows}}
                                    </dl>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</x-app-layout>

12-Create view file-  view-field.blade.php

<div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">

<dt class="text-sm font-medium leading-6 text-gray-900">{{title}}</dt>

<dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{{ ${{modelNameLowerCase}}->{{column}} }}</dd>

</div>

Leave a Reply