In this lesson, let's add the Delete button to our table.
Delete Button
Here's what we have in the Controller:
app/Http/Controllers/TaskController.php:
public function destroy(Task $task){ $task->delete(); return redirect()->route('tasks.index');}
Since we have Route::resource()
here, the React component should fire a DELETE request to the route /tasks/{ID}
.
So, first, we define the function inside the React component.
resources/js/pages/Tasks/Index.tsx:
import { Head } from '@inertiajs/react'; import { Head, router } from '@inertiajs/react'; // ... export default function Index({ tasks }: { tasks: Task[] }) { const deleteTask = (id: number) => { if (confirm('Are you sure?')) { router.delete(route('tasks.destroy', { id })); } }; // ...
Then, we need to add a Button to the table that calls the deleteTask()
method.
The Shadcn Button component is already installed in the starter kit, so we don't need to run any npx
commands. We just need to import it with button variants.
We add a new <TableCell>
to our <TableRow>
.
resources/js/pages/Tasks/Index.tsx:
import { Button, buttonVariants } from '@/components/ui/button'; // ... {tasks.map((task) => ( <TableRow key={task.id}> <TableCell>{task.name}</TableCell> <TableCell className={task.is_completed ? 'text-green-600' : 'text-red-700'}> {task.is_completed ? 'Completed' : 'In Progress'} </TableCell> <TableCell className="flex flex-row gap-x-2 text-right"> <Button variant={'destructive'} className={'cursor-pointer'} onClick={() => deleteTask(task.id)}> Delete </Button> </TableCell> </TableRow>))}
Here's the visual result:
Now, see that variant={'destructive'}
? To see what other button variants are available, look at this Shadcn documentation page.
Notice: In this course, we're adding custom Tailwind CSS classes to various components. I don't explicitly emphasize this, but it's pretty important: you must be good with Tailwind to customize the design to your needs.
If we click that Delete button, it will actually work: show a JS confirmation dialog and delete the task if confirmed.
For a better UX, we need to add the notification that the Delete action was successful.
Notifications with Toast/Sonner
To add a success alert/notification, we will use another Shadcn component called Sonner. They describe it as "opinionated toast component for React".
To install it, we run this command:
npx shadcn@latest add sonner
And this is where we get to a tricky situation with Shadcn and the latest (currently) React 19 version. See the warning in the Terminal:
It's not an error. The thing is: not all Shadcn components fully support the latest React 19. You can read more about it on this official Shadcn documentation page.
In our case, at the time of writing, we need to choose to Use --force
and proceed.
As a result, we have a new file resources/js/components/ui/sonner.tsx
created.
Now, we can use it in our React component.
First, we show that notification from our Index.tsx
file.
resources/js/pages/Tasks/Index.tsx:
import { toast } from 'sonner'; // ... export default function Index({ tasks }: { tasks: Task[] }) { const deleteTask = (id: number) => { if (confirm('Are you sure?')) { router.delete(route('tasks.destroy', { id })); toast.success('Task deleted successfully'); } };
And then, we need to define where we show that notification.
Let's do it in the Header, in the top-right corner. In the app-header-layout.tsx
, we need to import the <Toaster>
component on top and use it in the AppHeaderLayout()
function.
resources/js/layouts/app/app-header-layout.tsx:
import { AppShell } from '@/components/app-shell';import { type BreadcrumbItem } from '@/types';import type { PropsWithChildren } from 'react';import { Toaster } from '@/components/ui/sonner'; export default function AppHeaderLayout({ children, breadcrumbs }: PropsWithChildren<{ breadcrumbs?: BreadcrumbItem[] }>) { return ( <AppShell> ... <Toaster position={'top-right'} /> </AppShell> );}
As a result, if we delete a task, we see this in the top-right corner:
Success!
Here are the GitHub commits: first and second for this lesson.
In the next lesson, we will build the Create form of the CRUD.
Dear sir, can we can use
task
insteadid
? In route and controller we also use model binding