article

Wednesday, June 4, 2025

Laravel 12 Simple Inertia React Pagination Components | React Starter Kit

Laravel 12 Simple Inertia React Pagination Components | React Starter Kit

Download Laravel App

https://laravel.com/docs/12.x/installation

Connecting our Database

open .env file root directory.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=8889
DB_DATABASE=laravel12dev
DB_USERNAME=root
DB_PASSWORD=root

Database Migration
php artisan migrate

myapp>php artisan migrate
Migration table created successfully.
check database table

php artisan make:controller UsersController change it with the following codes:
app\Http\Controllers\UsersController.php

//app\Http\Controllers\UsersController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Inertia\Inertia;
use App\Models\User;

class UsersController extends Controller
{
    public function home()
    {
        $query = User::select('id', 'name', 'email', 'created_at')->latest();

        // Handle search
        if (request()->has('search')) {
            $search = request('search');
            $query->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%")
                    ->orWhere('email', 'like', "%{$search}%");
            });
        }

        $users = $query->paginate(10);

        return Inertia::render('users/index', [
            'users' => $users,
            'filters' => [
                'search' => request('search', ''),
            ]
        ]);
    }
}
Frontend with React and InertiaJS
Add sidebar menu product mainNavItems from reactjs\rescourses\js\components\app-sidebar.tsx
File: pages\users\index.tsx
reactjs\resources\js\pages\users\index.tsx
//reactjs\resources\js\pages\users\index.tsx
import AppLayout from '@/layouts/app-layout';
import { type BreadcrumbItem } from '@/types';
import { Head, router } from '@inertiajs/react';
import { Search } from 'lucide-react';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import Pagination from '@/components/Pagination'; 
import { useState } from 'react';

interface User {
    id: number;
    name: string;
    email: string;
    created_at: string;
}

interface Props {
    users: {
        data: User[];
        current_page: number;
        last_page: number;
        per_page: number;
        total: number;
        from: number;
        to: number;
    };
    filters: {
        search: string;
        filter: string;
    };
}

const breadcrumbs: BreadcrumbItem[] = [
    {
        title: 'Laravel 12 Simple Inertia React Pagination Components | React Starter Kit',
        href: '/admin/users',
    },
];

export default function UsersIndex({ users, filters }: Props) {
    //console.log(users); 
    const [searchTerm, setSearchTerm] = useState(filters.search);

    const handleSearch = (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();
        router.get(route('users.home'), {
            search: searchTerm,
        }, {
            preserveState: true,
            preserveScroll: true,
        });
    };
    return (
        <AppLayout breadcrumbs={breadcrumbs}>
            <Head title="Users" />
            <div className="flex h-full flex-1 flex-col gap-6 rounded-xl p-6 bg-gradient-to-br from-background to-muted/20">
                <div className="flex gap-4 mb-4">
                    <form onSubmit={handleSearch} className="relative flex-1">
                        <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
                        <Input placeholder="Search name or email..."
                            value={searchTerm}
                            onChange={(e) => setSearchTerm(e.target.value)}
                            className="pl-10 bg-gray-200  text-black"
                        />
                    </form>                                     
                </div>
                <div className="rounded-md border">
                    <div className="relative w-full overflow-auto">
                        <table className="w-full caption-bottom text-sm  bg-white rounded-lg">
                            <thead>
                                <tr className="bg-gray-200 text-black">
                                    <th className="py-2 px-4 text-left border-b">ID</th>
                                    <th className="py-2 px-4 text-left border-b">Name</th>
                                    <th className="py-2 px-4 text-left border-b">Email</th>
                                    <th className="py-2 px-4 text-left border-b">Created At</th>                                   
                                    <th className="py-2 px-4 text-right border-b">Actions</th>                                
                                </tr>                            
                            </thead>   
                            <tbody>
                                {users.data.map((user) => (
                                    <tr key={user.id} className="hover:bg-gray-50 text-black">
                                        <td className="p-4 align-middle font-medium border-b">{user.id}</td>
                                        <td className="p-4 align-middle font-medium border-b">{user.name}</td>
                                        <td className="p-4 align-middle font-medium border-b">{user.email}</td>
                                        <td className="p-4 align-middle font-medium border-b">{new Date(user.created_at).toLocaleDateString()}</td>
                                        <td className="p-4 align-middle text-right border-b">
                                            <div className="flex justify-end gap-2">
                                                <Button variant="ghost"
                                                    className="w-full sm:w-auto bg-blue-600 text-white rounded-lg px-4 py-2 hover:bg-blue-700"
                                                >
                                                    Edit
                                                </Button>                                                
                                                <Button variant="ghost"
                                                    className="w-full sm:w-auto bg-red-600 text-white rounded-lg px-4 py-2 hover:bg-red-700 transition transition ml-2"
                                                >
                                                    Delete
                                                </Button>                                            
                                            </div>
                                        </td>
                                    </tr>
                                ))}
                                {users.total === 0 && (
                                    <tr>
                                        <td colSpan={6} className="p-4 text-center text-muted-foreground">
                                            No users Found                                        
                                        </td>
                                    </tr>
                                )}
                            </tbody> 
                        </table>              
                    </div>                
                </div>
                {/* Pagination */}
                <div className="flex items-center justify-between px-2">
                    <div className="text-sm text-muted-foreground">
                        Showing {users.from} to {users.to} of {users.total} results  
                    </div>                    
                    <div className="flex items-center space-x-2">
                    <Pagination links={users.links}/>                  
                    </div>                
                </div> 
            </div>
        </AppLayout>
    );
}
File: js\components\Pagination.tsx
reactjs\resources\js\components\Pagination.tsx
//reactjs\resources\js\components\Pagination.tsx
import { Link } from '@inertiajs/react'

export default function Pagination({ links }) {
    console.log(links);
    return (
        <div className="flex flex-wrap items-center space-x-1 mt-4">
            {links.map((link, index) => (
                <Link 
                    key={index}    
                    href={link.url ?? '#'}
                    dangerouslySetInnerHTML={{ __html: link.label}}
                    className={`text-lg rounded-lg px-4 py-2 border gap-2
                        ${link.active ? 'border-t-blue-600 text-white  bg-blue-600' : 'bg-white text-gray-700'}
                        ${!link.url ? 'opacity-50 pointer-events-none' : 'hover:bg-gray-100'}`}
                />
            ))}
        </div>
    )
}
php artisan tinker
User::factory()->count(1000)->create()
Routes
routes/web.php
//routes/web.php
<?php

use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use App\Http\Controllers\UsersController;

Route::get('/', function () {
    return Inertia::render('welcome');
})->name('home');

Route::middleware(['auth', 'verified'])->group(function () {
    Route::get('dashboard', function () {
        return Inertia::render('dashboard');
    })->name('dashboard');

    Route::get('/admin/users-pagination-search', [UsersController::class, 'home'])->name('users.home');
});

require __DIR__.'/settings.php';
require __DIR__.'/auth.php';
Run php artisan serve and npm run dev myapp>composer run dev
Starting Laravel development server: http://127.0.0.1:8000

Related Post