Build the Delete Button with Confirmation
Build the Delete Button with Confirmation
Deleting is destructive, so it needs a browser confirm() dialog before it
fires. confirm() only exists in the browser — it can’t run inside a
Server Component, which executes on the server. This is the one spot in
the app that genuinely needs a Client Component.
Create components/DeleteContactButton.tsx:
"use client";
import { useTransition } from "react";
import { deleteContactAction } from "@/lib/actions";
export default function DeleteContactButton({ id, name }: { id: string; name: string }) {
const [isPending, startTransition] = useTransition();
return (
<button
type="button"
className="btn btn-danger"
disabled={isPending}
onClick={() => {
if (confirm(`Delete ${name} from your contact book? This can't be undone.`)) {
startTransition(() => {
deleteContactAction(id);
});
}
}}
>
{isPending ? "Deleting…" : "Delete"}
</button>
);
}
A few things worth understanding:
"use client"at the top of the file tells Next.js this component runs
in the browser, not the server. It’s needed here specifically because
ofconfirm()and the interactiveonClickhandler — not because
Server Actions themselves require it. You just saw a Server Action
called from a plain Server Component form in the last lesson.- A Server Action is still just an async function — you can call it
directly from a Client Component’s event handler, not only from a
form’sactionprop. That’s what’s happening inonClick. useTransitiongives youisPending, so the button can show
“Deleting…” and disable itself while the Server Action is in flight,
preventing a double-click from firing it twice.
Add it to the contact detail page
Open app/contacts/[id]/page.tsx:
import DeleteContactButton from "@/components/DeleteContactButton";
// ...inside detail-actions:
<div className="detail-actions">
<Link href={`/contacts/${contact.id}/edit`} className="btn btn-ghost">Edit</Link>
<Link href="/" className="btn btn-ghost">Back to all contacts</Link>
<DeleteContactButton id={contact.id} name={contact.name} />
</div>
Test it
Open a contact’s detail page and click Delete. You should get a browser
confirmation dialog with that contact’s name in it. Cancel it — nothing
should happen. Click Delete again and confirm — you should be redirected
to the Home page, and that contact should be gone from the list.
Checkpoint
You can delete a contact after confirming, and you can now point to the
exact line ("use client") that separates this component from every other
one in the app so far, and explain why it’s there.