This script adds a playful tab-title effect. When users switch away from your site, it replaces the tab title with fun custom messages (in sequence or random order). It can sync messages across multiple tabs, rotate them automatically, and restores the original title as soon as the user returns.
// Messages (add as many as you like)
const tabMessages = [
"👀 Miss me?",
"✨ Still waiting…",
"😏 Don’t ghost me.",
"🔥 Come back 😉",
"💋 Miss your clicks."
];
// Settings
const startDelay = 2000; // Wait before showing message (ms)
const rotateSpeed = 2000; // How fast to switch (ms)
const returnDelay = 1000; // Delay before title resets (ms)
const useRandom = true; // true = random order, false = rotate in order
const rotateMessages = true; // true = keep rotating, false = show one only
const syncMessages = true; // true = sync all tabs to same message, false = independent
(function () {
if (/Mobi|Android/i.test(navigator.userAgent)) return;
let originalTitle = document.title;
let index = 0;
let lastRandom = -1;
let interval = null;
let startTimer = null;
let returnTimer = null;
function clearTimers() {
clearInterval(interval);
clearTimeout(startTimer);
}
function getMessage() {
if (tabMessages.length === 0) return originalTitle;
if (useRandom && tabMessages.length > 1) {
let i;
do { i = Math.floor(Math.random() * tabMessages.length); } while (i === lastRandom);
lastRandom = i;
return tabMessages[i];
}
const msg = tabMessages[index];
index = (index + 1) % tabMessages.length;
return msg;
}
function setMessage(msg) {
document.title = msg;
if (syncMessages) {
localStorage.setItem("site_tab_message", msg);
}
}
function startEffect() {
clearTimers();
if (tabMessages.length === 1) {
setMessage(tabMessages[0]);
return;
}
setMessage(getMessage());
if (rotateMessages) {
interval = setInterval(() => {
setMessage(getMessage());
}, rotateSpeed);
}
}
function restore() {
clearTimers();
clearTimeout(returnTimer);
returnTimer = setTimeout(() => {
document.title = originalTitle;
if (syncMessages) {
localStorage.removeItem("site_tab_message");
}
}, returnDelay);
}
function queueStart() {
clearTimers();
clearTimeout(startTimer);
startTimer = setTimeout(startEffect, startDelay);
}
function setActive(state) {
localStorage.setItem("site_tab_active", state ? "1" : "0");
}
function isAnyTabActive() {
return localStorage.getItem("site_tab_active") === "1";
}
function handleVisibility() {
if (document.hidden) {
if (!isAnyTabActive()) queueStart();
setActive(false);
} else {
setActive(true);
restore();
}
}
window.addEventListener("storage", (e) => {
if (e.key === "site_tab_active") {
if (isAnyTabActive()) {
restore();
} else {
queueStart();
}
}
if (syncMessages && e.key === "site_tab_message" && e.newValue) {
document.title = e.newValue;
}
});
document.addEventListener("visibilitychange", handleVisibility);
window.addEventListener("blur", handleVisibility);
window.addEventListener("focus", handleVisibility);
if (!document.hidden) setActive(true);
})();
Some solutions only work on the live site. Always publish and test after each change, as results may not appear in the editor.