React and Next.js WhatsApp Widget: Component Code and Install Instructions
React WhatsApp button and a Next.js compatible component that works in both the App Router and the Pages Router. The component is fully typed, supports a dynamic phone number from props, and includes a small server-action-ready example for Next.js 14+. Target link: wa.me/966500000000.
1. The React component (TSX)
Create components/WuttWhatsApp.tsx:
import { CSSProperties, MouseEvent } from "react";
export type WuttWhatsAppProps = {
phone: string;
message?: string;
label?: string;
position?: "bottom-right" | "bottom-left";
onClick?: (e: MouseEvent<HTMLAnchorElement>) => void;
};
export default function WuttWhatsApp({
phone,
message = "Hi, I'd like to know more about Wutt.",
label = "Chat with us",
position = "bottom-right",
onClick,
}: WuttWhatsAppProps) {
const digits = phone.replace(/\D/g, "");
const href = `https://wa.me/${digits}?text=${encodeURIComponent(message)}`;
const style: CSSProperties = {
position: "fixed",
[position === "bottom-left" ? "left" : "right"]: 20,
bottom: 20,
zIndex: 9999,
display: "inline-flex",
alignItems: "center",
gap: 10,
background: "#25D366",
color: "#fff",
padding: "12px 18px",
borderRadius: 999,
textDecoration: "none",
fontWeight: 700,
boxShadow: "0 10px 30px rgba(0,0,0,.25)",
};
return (
<a href={href} target="_blank" rel="noopener" style={style} onClick={onClick} aria-label="Chat on WhatsApp">
<svg viewBox="0 0 32 32" width="22" height="22" aria-hidden="true">
<path fill="#fff" d="M16 3C9 3 3.5 8.5 3.5 15.5c0 2.4.7 4.7 1.9 6.7L3 29l7-1.8c1.9 1 4 1.5 6 1.5 7 0 12.5-5.5 12.5-12.5S23 3 16 3z" />
</svg>
<span>{label}</span>
</a>
);
}
2. Next.js App Router usage
App Router lives in app/. To load the widget on every page, create app/components/WuttClient.tsx that imports the component with "use client":
"use client";
import dynamic from "next/dynamic";
const WuttWhatsApp = dynamic(() => import("./WuttWhatsApp"), { ssr: false });
export default function WuttClient() {
return (
<WuttWhatsApp
phone="966500000000"
message="Hi, I'd like to know more about Wutt."
label="Chat"
/>
);
}
Then drop it into app/layout.tsx:
import WuttClient from "./components/WuttClient";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<WuttClient />
</body>
</html>
);
}
The dynamic(..., { ssr: false }) import prevents the widget from being rendered on the server — useful because the link is client-side-only and avoids hydration warnings.
3. Pages Router usage
If you're on the Pages Router, drop the import into pages/_app.tsx:
import type { AppProps } from "next/app";
import WuttWhatsApp from "../components/WuttWhatsApp";
export default function MyApp({ Component, pageProps }: AppProps) {
return (
<>
<Component {...pageProps} />
<WuttWhatsApp
phone="966500000000"
message="Hi, I'd like to know more about Wutt."
/>
</>
);
}
4. Dynamic phone number from props
For a multi-tenant store or a multi-branch site, pass the phone down through props, a context, or a server-fetched value. Here's a CMS-driven example using a server component that passes the phone to a client component:
// app/[branch]/page.tsx (Server Component)
import { notFound } from "next/navigation";
import WuttClient from "../components/WuttClient";
async function getBranch(slug: string) {
const res = await fetch(`https://cms.example.com/branches/${slug}`, { cache: "no-store" });
if (!res.ok) return null;
return res.json();
}
export default async function BranchPage({ params }: { params: { branch: string } }) {
const branch = await getBranch(params.branch);
if (!branch) notFound();
return (
<main>
<h1>{branch.name}</h1>
<p>{branch.address}</p>
<WuttClient phone={branch.whatsapp} message={`Hi, I'm at the ${branch.name} branch.`} />
</main>
);
}
If you don't have a CMS yet, use a small environment lookup:
// app/components/WuttClient.tsx
"use client";
import WuttWhatsApp from "./WuttWhatsApp";
export default function WuttClient() {
return <WuttWhatsApp phone={process.env.NEXT_PUBLIC_WUTT_PHONE || "966500000000"} />;
}
Server actions (Next.js 14+)
To log a click into your own analytics before opening WhatsApp, hook into a server action:
// app/actions.ts
"use server";
export async function logWuttClick(phone: string) {
// e.g. await fetch("https://api.wutt.net/v1/clicks", { method: "POST", body: JSON.stringify({ phone }) });
return { ok: true };
}
// components/WuttWhatsApp.tsx (excerpt)
import { logWuttClick } from "@/app/actions";
const onClick = async () => { await logWuttClick(digits); };
// pass to <a onClick={onClick}>
Add Wutt to your site — start $1 trial
Drop the widget in, then keep every reply, click, lead, and order inside Wutt Inbox, Wutt Book, Wutt Reviews, Wutt Loyalty, and the CRM follow-up workspace.
Start $1 trial