First-Visit Announcement Bar

November 25, 2025

First-Visit Announcement Bar with localStorage (No Cookies, No Frameworks)

Sometimes you want to say something to new visitors without nagging people who visit every day. A short “Welcome” message, a note about a new feature, or an important update is useful once, but gets old fast if it keeps appearing on every page.

This snippet solves that with a tiny, cookie-free announcement bar that only shows on a visitor’s first visit (or first visit per campaign key). It uses localStorage to remember dismissal and stays completely on the front end: no backend, no tracking pixels, and no layout changes beyond a slim bar at the top.

What this snippet does

A tiny announcement bar that only shows on a visitor’s first visit using localStorage. Great for “New here?” messages, promos or important updates without nagging regulars. No cookies, no frameworks, just a small drop-in snippet.

How it works:

  • Shows a fixed bar at the top on the visitor’s first page view.
  • When they click “× Close”, the bar fades out and sets a flag in localStorage.
  • On future visits, the script sees the flag and never shows the bar again.
  • You can change the text, link, colors and storage key in one place.

Because it lives entirely in the browser and writes a single key to localStorage, it’s a simple way to handle one-time “welcome” style messaging without introducing a full consent-management flow or a complex notification system.

Installation

Install: Paste the snippet right before </body> on your page (ideally in a common footer include if you have one). Any page that includes it will show the bar once for visitors who haven’t dismissed it yet.

<!-- First-Visit Announcement Bar (VibeScriptz) -->
<div
  id="vs-announce-bar"
  class="vs-announce-bar"
  data-vs-key="vs_announce_seen_main"
>
  <div class="vs-announce-inner">
    <span class="vs-announce-text">
      New here? 👋 Check out our most popular script:
      <a href="/script/dark-mode-toggle-with-local-storage-no-frameworks/">
        Dark Mode Toggle
      </a>
    </span>
    <button class="vs-announce-close" type="button" aria-label="Close">
      ×
    </button>
  </div>
</div>

<style>
/* --- First-Visit Announcement Bar (no frameworks, no cookies) --- */
.vs-announce-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 9999;
  background: #111;
  color: #f5f5f5;
  transform: translateY(-100%);
  opacity: 0;
  transition: transform 0.25s ease-out, opacity 0.25s ease-out;
  font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
    sans-serif;
  font-size: 14px;
}

.vs-announce-visible {
  transform: translateY(0);
  opacity: 1;
}

.vs-announce-hiding {
  opacity: 0;
}

.vs-announce-inner {
  max-width: 1100px;
  margin: 0 auto;
  padding: 8px 12px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.vs-announce-text {
  flex: 1;
  line-height: 1.4;
}

.vs-announce-text a {
  color: #ffd86b;
  text-decoration: underline;
}

.vs-announce-text a:hover {
  color: #ffe9a6;
}

.vs-announce-close {
  border: 0;
  background: #444;
  color: #fff;
  cursor: pointer;
  border-radius: 999px;
  width: 24px;
  height: 24px;
  line-height: 24px;
  padding: 0;
  text-align: center;
  font-size: 16px;
}

.vs-announce-close:hover {
  background: #666;
}

/* Slightly smaller on narrow screens */
@media (max-width: 600px) {
  .vs-announce-inner {
    padding: 6px 10px;
    font-size: 13px;
  }
}
</style>

<script>
/*
 * First-Visit Announcement Bar
 * - Uses localStorage only (no cookies)
 * - Change data-vs-key if you want a separate bar per campaign
 */
(function () {
  var bar = document.getElementById("vs-announce-bar");
  if (!bar) return;

  var storageKey = bar.getAttribute("data-vs-key") || "vs_announce_seen";

  // If we've already seen this announcement, remove the bar and bail
  try {
    if (window.localStorage && localStorage.getItem(storageKey) === "1") {
      bar.parentNode.removeChild(bar);
      return;
    }
  } catch (e) {
    // localStorage might be blocked; fail silently and just show the bar
  }

  // Show bar
  bar.classList.add("vs-announce-visible");

  function hideBar() {
    bar.classList.remove("vs-announce-visible");
    bar.classList.add("vs-announce-hiding");

    // Remove from DOM after fade
    setTimeout(function () {
      if (bar && bar.parentNode) {
        bar.parentNode.removeChild(bar);
      }
    }, 300);

    // Remember dismissal
    try {
      if (window.localStorage) {
        localStorage.setItem(storageKey, "1");
      }
    } catch (e) {}
  }

  // Close on button click
  bar.addEventListener("click", function (evt) {
    if (
      evt.target.classList.contains("vs-announce-close") ||
      evt.target.closest(".vs-announce-close")
    ) {
      hideBar();
    }
  });
})();
</script>

Customizing the bar

Customize it:

  • Change the text and link inside .vs-announce-text to point at your own docs, scripts, newsletter, or onboarding page.
  • Tweak colors in the CSS (background: #111;, link colors, button background) so the bar matches your site’s palette.
  • Change data-vs-key if you want a different bar for a new promo, for example vs_announce_black_friday or vs_announce_new_feature.
  • To make it show again for yourself, clear localStorage for this site or open the page in a private window / another browser profile.

Because the storage key is just a string, you can safely rotate campaigns by assigning each one a unique key. The old key stays in localStorage as history, and the new key controls whether the new announcement appears.

When this pattern makes sense

A first-visit announcement bar works well for:

  • Highlighting one “flagship” script or feature for brand new visitors.
  • Short-lived promotions where you don’t want to redesign your entire header.
  • Important notices (e.g., “We just shipped a big update”) that shouldn’t nag regulars.

It’s less suited for time-critical alerts that must be seen on every single visit, or for legal messages that require explicit acknowledgement. Those usually need a different UX and sometimes a proper consent log.

Accessibility and UX notes

The bar uses a close button with an aria-label so screen readers can announce what it does. You can extend this by:

  • Adding more descriptive text to the message so it stands on its own.
  • Ensuring the contrast between background and text passes accessibility guidelines.
  • Keeping the announcement short so it doesn’t cover too much of the viewport.

Because the bar appears at the top and can be dismissed permanently, it stays relatively polite compared to heavy-handed modals or full-screen overlays, while still being visible enough for new visitors to notice.

If you ever decide you don’t want the behavior anymore, you can remove the HTML, CSS, and script block from your layout and any existing localStorage keys will simply become unused data in the browser.

Comments (0)

No comments yet — be the first.

← Back to all scripts