HTML and JavaScript WhatsApp Widget: Copy-Paste Button, CSS, and Script
WhatsApp button HTML with self-contained HTML, CSS, and JavaScript. Drop the block below into any page, inside a CMS, a static site, or a documentation portal. It includes a floating chat icon, a hover tooltip, a "Chat with us" pill, and mobile-aware positioning so the button never collides with the bottom mobile bar. Phone used: wa.me/966500000000.
Quick install (one block)
Paste the entire block right before </body> on any HTML page. The widget is self-contained, has no external dependencies, and styles itself with a #wutt-wa-* namespace so it won't clash with your CSS:
<!-- Wutt WhatsApp widget -->
<div id="wutt-wa-root" aria-live="polite">
<a id="wutt-wa-button"
href="https://wa.me/966500000000?text=Hi%2C%20I'd%20like%20to%20know%20more%20about%20Wutt."
target="_blank" rel="noopener"
aria-label="Chat on WhatsApp">
<span id="wutt-wa-tooltip">Chat with us</span>
<span id="wutt-wa-icon" aria-hidden="true">
<svg viewBox="0 0 32 32" width="28" height="28">
<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 3zm5.6 15.2c-.3-.2-1.8-.9-2.1-1-.3-.1-.5-.2-.7.2-.2.3-.8 1-1 1.2-.2.2-.4.2-.7.1-.3-.2-1.3-.5-2.5-1.5-.9-.8-1.5-1.8-1.7-2.1-.2-.3 0-.5.1-.7.1-.1.3-.4.4-.5.1-.2.2-.3.3-.5.1-.2 0-.4 0-.5 0-.2-.7-1.7-1-2.3-.3-.6-.5-.5-.7-.5h-.6c-.2 0-.5.1-.8.4-.3.3-1 1-1 2.5s1.1 2.9 1.2 3.1c.1.2 2.1 3.2 5.1 4.5 1.7.7 2.4.8 3.3.6.5-.1 1.5-.6 1.7-1.2.2-.6.2-1.1.1-1.2 0-.1-.2-.2-.5-.4z"/>
</svg>
</span>
<span id="wutt-wa-pulse" aria-hidden="true"></span>
</a>
</div>
<style>
#wutt-wa-root{font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif}
#wutt-wa-button{
position:fixed;right:20px;bottom:20px;z-index:9999;
display:inline-flex;align-items:center;gap:10px;
background:#25D366;color:#fff;
padding:12px 18px 12px 14px;border-radius:999px;
text-decoration:none;font-weight:700;font-size:14px;
box-shadow:0 10px 30px rgba(0,0,0,.25);
transition:transform .15s ease,box-shadow .15s ease
}
#wutt-wa-button:hover{transform:translateY(-2px);box-shadow:0 14px 36px rgba(0,0,0,.3)}
#wutt-wa-icon{
width:32px;height:32px;border-radius:50%;background:#1ebe5d;
display:inline-flex;align-items:center;justify-content:center;flex:none
}
#wutt-wa-tooltip{
position:absolute;right:calc(100% + 8px);top:50%;transform:translateY(-50%);
background:#0a0a0a;color:#fff;padding:6px 10px;border-radius:6px;
font-size:12px;white-space:nowrap;opacity:0;pointer-events:none;
transition:opacity .15s ease,transform .15s ease
}
#wutt-wa-button:hover #wutt-wa-tooltip{opacity:1;transform:translateY(-50%) translateX(-4px)}
#wutt-wa-pulse{
position:absolute;inset:0;border-radius:999px;
box-shadow:0 0 0 0 rgba(37,211,102,.55);
animation:wutt-wa-pulse 2.4s infinite;pointer-events:none
}
@keyframes wutt-wa-pulse{
0% {box-shadow:0 0 0 0 rgba(37,211,102,.55)}
70% {box-shadow:0 0 0 18px rgba(37,211,102,0)}
100%{box-shadow:0 0 0 0 rgba(37,211,102,0)}
}
/* Hide the inline label on small screens, show the icon only */
@media (max-width:600px){
#wutt-wa-button{padding:10px;right:14px;bottom:14px}
#wutt-wa-button > #wutt-wa-pulse{ /* keep pulse on the icon-only mode */ }
}
</style>
<script>
(function () {
// Configuration - edit phone, default message, or label without touching CSS.
var CFG = {
phone: "966500000000", // E.164 digits only
message: "Hi, I'd like to know more about Wutt.",
storageKey: "wutt_wa_dismissed_until"
};
function ready(fn){ if(document.readyState!=="loading"){fn()}else{document.addEventListener("DOMContentLoaded",fn)} }
ready(function () {
var btn = document.getElementById("wutt-wa-button");
if (!btn) return;
// Respect "do not show again" stored value (30 days)
var dismissedUntil = parseInt(localStorage.getItem(CFG.storageKey) || "0", 10);
if (Date.now() < dismissedUntil) return;
// Build the deep link
var href = "https://wa.me/" + CFG.phone.replace(/\D/g, "") + "?text=" + encodeURIComponent(CFG.message);
btn.setAttribute("href", href);
// Optional analytics hook: dispatch a CustomEvent so GA4 / GTM can listen.
btn.addEventListener("click", function () {
try {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ event: "wutt_wa_click", phone: CFG.phone });
} catch (e) {}
});
// Hide the inline label on phones, keep the icon
var tooltip = document.getElementById("wutt-wa-tooltip");
function syncLayout() {
if (window.innerWidth <= 600) {
if (tooltip) tooltip.style.display = "none";
btn.lastChild && btn.lastChild.nodeType === 3 && (btn.lastChild.textContent = "");
} else {
if (tooltip) tooltip.style.display = "";
}
}
syncLayout();
window.addEventListener("resize", syncLayout);
});
})();
</script>
What you get
- Floating button — fixed bottom-right, animates on hover, pulse ring to draw attention.
- Hover tooltip — "Chat with us" label appears next to the button on desktop.
- Mobile-aware — collapses to icon-only under 600px and stays clear of the iOS safe area.
- Pre-filled message — opens WhatsApp with "Hi, I'd like to know more about Wutt." so customers don't start with a blank chat.
- No external dependencies — no jQuery, no fonts, no CDNs. Just one HTML, one CSS block, and one script.
- Analytics hook — pushes
wutt_wa_clickintowindow.dataLayerfor GTM / GA4.
Customization recipes
Change the phone or message in the CFG object at the top of the script. To set a different default message per page, set window.WUTT_WA_MESSAGE = "..." before the script runs and the widget will pick it up:
<script>window.WUTT_WA_MESSAGE = "Hi, I have a question about pricing.";</script>
<!-- include the widget code below -->
Want to delay the button on first scroll so it doesn't steal attention above the fold? Add this snippet above the widget:
<script>
window.addEventListener("scroll", function once() {
document.getElementById("wutt-wa-root").style.opacity = "1";
window.removeEventListener("scroll", once);
}, { once: true });
</script>
Accessibility
- The button has
aria-label="Chat on WhatsApp"for screen readers. - The icon is
aria-hidden="true"so it isn't read twice. - The pulse is a decorative element only and is also
aria-hidden. - The wrapper carries
aria-live="polite"only as a hook if you later add a status text.
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