Kritim Yantra
Jun 10, 2025
Imagine building a LEGO castle:
No glue, no duct tape β everything snaps together perfectly! Today, weβll build a fully functional Todo app without writing a single API endpoint. Letβs dive in!
laravel new inertia-todo
cd inertia-todo
composer require inertiajs/inertia-laravel
npm install @inertiajs/react react react-dom
Update resources/views/app.blade.php
:
<!DOCTYPE html>
<html>
<head>
@vite('resources/js/app.js')
</head>
<body>
<div id="app" data-page="{{ json_encode($page) }}"></div>
</body>
</html>
Create resources/js/app.js
:
import { createInertiaApp } from '@inertiajs/react';
import { createRoot } from 'react-dom/client';
createInertiaApp({
resolve: name => require(`./Pages/${name}`),
setup({ el, App, props }) {
createRoot(el).render(<App {...props} />);
},
});
php artisan make:model Todo -m
Edit migration file (database/migrations/..._create_todos_table.php
):
public function up() {
Schema::create('todos', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->boolean('completed')->default(false);
$table->timestamps();
});
}
Run migration:
php artisan migrate
php artisan make:controller TodoController
Edit app/Http/Controllers/TodoController.php
:
use App\Models\Todo;
use Inertia\Inertia;
use Illuminate\Http\Request;
class TodoController extends Controller {
// Show all todos
public function index() {
return Inertia::render('Todos/Index', [
'todos' => Todo::latest()->get()
]);
}
// Add new todo
public function store(Request $request) {
Todo::create($request->validate(['title' => 'required|min:3']));
return redirect()->back();
}
// Update completion status
public function update(Request $request, Todo $todo) {
$todo->update(['completed' => $request->completed]);
return redirect()->back();
}
// Delete todo
public function destroy(Todo $todo) {
$todo->delete();
return redirect()->back();
}
}
Edit routes/web.php
:
use App\Http\Controllers\TodoController;
Route::get('/', [TodoController::class, 'index']);
Route::post('/todos', [TodoController::class, 'store']);
Route::put('/todos/{todo}', [TodoController::class, 'update']);
Route::delete('/todos/{todo}', [TodoController::class, 'destroy']);
resources/js/Pages/Todos/Index.jsx
)import { Head, Link } from '@inertiajs/react';
import TodoForm from './Form';
import TodoList from './List';
export default function TodoIndex({ todos }) {
return (
<div className="max-w-2xl mx-auto p-8">
<Head title="Your Todo List" />
<h1 className="text-3xl font-bold mb-6">β¨ Your Todo List</h1>
<TodoForm />
<TodoList todos={todos} />
</div>
);
}
resources/js/Pages/Todos/Form.jsx
)import { useForm } from '@inertiajs/react';
export default function TodoForm() {
const { data, setData, post, processing } = useForm({
title: ''
});
const submit = (e) => {
e.preventDefault();
post('/todos');
};
return (
<form onSubmit={submit} className="mb-8">
<input
type="text"
value={data.title}
onChange={e => setData('title', e.target.value)}
placeholder="Buy groceries..."
className="w-full p-3 border rounded"
disabled={processing}
/>
<button
type="submit"
className="mt-2 bg-blue-500 text-white p-2 rounded"
disabled={processing}
>
{processing ? 'Adding...' : 'Add Task'}
</button>
</form>
);
}
resources/js/Pages/Todos/List.jsx
)import { Link } from '@inertiajs/react';
export default function TodoList({ todos }) {
return (
<div className="space-y-4">
{todos.map(todo => (
<div key={todo.id} className="flex items-center justify-between p-4 bg-white shadow rounded">
<div className="flex items-center">
<input
type="checkbox"
checked={todo.completed}
onChange={() => Inertia.put(`/todos/${todo.id}`, {
completed: !todo.completed
})}
className="mr-3 h-5 w-5"
/>
<span className={todo.completed ? 'line-through text-gray-500' : ''}>
{todo.title}
</span>
</div>
<button
onClick={() => Inertia.delete(`/todos/${todo.id}`)}
className="text-red-500 hover:text-red-700"
>
Delete
</button>
</div>
))}
</div>
);
}
php artisan serve
npm run dev
http://localhost:8000
Behold! Your fully functional Todo app:
User adds task:
store()
method β Database User checks todo:
update()
method User deletes item:
destroy()
π‘ Pro Tip: Add Laravel Breeze for authentication:
composer require laravel/breeze --dev php artisan breeze:install react
Enhance your Todo app with:
Questions? Drop them below! π
No comments yet. Be the first to comment!
Please log in to post a comment:
Sign in with Google