How To

How to add a dismissible, session-based info banner in Webflow (without cookies)

Preferred source on google logo
How to add a dismissible, session-based info banner in Webflow (without cookies)
February 18, 2025

  · 5 min

How to add a dismissible info banner to Webflow using sessionStorage and plain JavaScript: no cookies, attribute-based, and it shows again each new session.

Ever needed a way to show an info banner in Webflow that users can dismiss, but then have it reappear on their next visit? Maybe for an announcement, a promo, or some friendly "hey, this is important" messaging. But here’s the catch: you don’t want to mess around with cookies, and you want it to be Webflow-friendly.

That’s exactly what this little JavaScript snippet does. It uses sessionStorage to keep things simple: no cookies, no bloated scripts, just a clean, efficient way to show a banner per session and let users hide it while they browse. We had to create this for a client a while back and now we're sharing it. Let’s break it down step by step. You might find some redundancy here, but it was specific to that project and we had to fix some issues that came up, so we left it in. There's also a handy cloneable at the very bottom of the post with the actual script running. Feel free to customise. If you’re weighing up cookies and consent more generally, we also wrote about what happens to your analytics data when most visitors decline cookies.

What this script does

  • Shows a banner when a user starts a new session (aka, when they open your site in a new tab or after closing the browser).
  • Lets them dismiss it, and keeps it hidden while they browse.
  • Resets every session, so next time they visit, the banner shows up again.
  • Uses only attributes for easy Webflow integration (no need for classes).
  • No cookies needed: it’s all handled with sessionStorage.

How to set it up in Webflow

1. Add the banner in Webflow

Inside Webflow, add a simple div block for your banner and a button to close it. But instead of using classes, we’ll use custom attributes.

Structure:

<div banner-element="banner-component">
  <p>This is an important message for your visitors.</p>
  <button banner-element="close">Got it</button>
</div>

Why attributes? They make it easier to manage in Webflow, especially when working with dynamic content. No need to worry about class naming conflicts. Super easy, name your classes the way you want. (If you’re still deciding on a class naming system, we wrote about whether Finsweet Client-First is right for you.)

2. Paste this script in Webflow

Now, go to Webflow's Custom Code settings and add this script right before <!-- fs-richtext-ignore --></body>.

<script>
document.addEventListener('DOMContentLoaded', function () {
  function initializeBanner() {
    const banner = document.querySelector('[banner-element="banner-component"]');
    const closeButton = document.querySelector('[banner-element="close"]');

    if (!banner || !closeButton) {
      return;
    }

    banner.style.visibility = 'visible';

    if (!sessionStorage.getItem('banner-closed')) {
      banner.style.opacity = '1';
    } else {
      banner.style.display = 'none';
    }

    closeButton.addEventListener('click', function () {
      banner.style.opacity = '0';
      setTimeout(() => {
        banner.style.display = 'none';
      }, 300);
      sessionStorage.setItem('banner-closed', 'true');
    });
  }

  const observer = new MutationObserver((mutations, obs) => {
    if (
      document.querySelector('[banner-element="banner-component"]') &&
      document.querySelector('[banner-element="close"]')
    ) {
      initializeBanner();
      obs.disconnect();
    }
  });

  observer.observe(document.body, { childList: true, subtree: true });
});
</script>

Why place it before <!-- fs-richtext-ignore --></body>? It ensures that all elements have loaded before the script runs, preventing errors where the script tries to select elements that don’t exist yet. If you’d like help writing or tweaking custom code like this, see our post on writing custom code for Webflow with ChatGPT.

How it works

Now for the fun part: what’s actually happening inside the script?

Flow diagram of the five script steps: find the elements, make the banner visible, check sessionStorage, handle the close click, wait for the elements

Step 1: Find the banner & close button

The script looks for two things:

  • The banner ([banner-element="banner-component"])
  • The close button ([banner-element="close"])

If either is missing, the script stops running to avoid errors.

Step 2: Make the banner visible

Webflow sometimes loads elements hidden by default, so we ensure the banner is visible by setting:

banner.style.visibility = 'visible';

(I think the client we originally wrote this for had the banner element set to hidden)

Step 3: Check session storage

The magic ingredient: sessionStorage.

if (!sessionStorage.getItem('banner-closed')) {
  banner.style.opacity = '1';
} else {
  banner.style.display = 'none';
}

This means:

  • If the banner hasn’t been closed in this session → it shows.
  • If the user closed it already in this session → it stays hidden.
  • The script only switches the opacity to 1, so in the Designer you can start the banner element at 0% opacity with a 300ms opacity transition. It then fades in, and fades out again when it is closed.

Step 4: Handle the close button click

When the user clicks the close button, we:

  • Fade out the banner.
  • Wait 300ms for the transition to finish.
  • Fully hide the banner (display: none;).
  • Store that they closed it in sessionStorage.
closeButton.addEventListener('click', function () {
  banner.style.opacity = '0';
  setTimeout(() => {
    banner.style.display = 'none';
  }, 300);
  sessionStorage.setItem('banner-closed', 'true');
});

Step 5: MutationObserver for Webflow elements

Webflow sometimes loads elements dynamically, so the script waits until the banner and the close button exist before running:

const observer = new MutationObserver((mutations, obs) => {
 if (
   document.querySelector('[banner-element="banner-component"]') &&
   document.querySelector('[banner-element="close"]')
 ) {
   initializeBanner();
   obs.disconnect();
 }
});

const observer = new MutationObserver((mutations, obs) => {
  if (
    document.querySelector('[banner-element="banner-component"]') &&
    document.querySelector('[banner-element="close"]')
  ) {
    initializeBanner();
    obs.disconnect();
  }
});

This helps the script cope when Webflow loads things a bit late. We use the same waiting-for-the-element idea in our post on optimising Vimeo background videos with an intersection observer.

(If I remember correctly, the client either had a ton of JavaScript or videos loading and things got delayed, and then the script was ready but the banner wasn't).

One honest caveat: a MutationObserver only reacts to changes that happen after it starts watching, and this script has no separate check for elements that are already on the page. If the banner and button are already there and nothing else gets added to the page afterwards, the observer never fires and the banner stays in its hidden start state. In a quick test on a plain static page, that is exactly what happened. So if your banner never shows, check this first.

Done! No more persistent banners

Now you have a session-based dismissible banner in Webflow that:

  • Shows up every new session (not permanently hidden).
  • Lets users hide it without cookies.
  • Uses attributes-only for Webflow-friendliness.
  • Copes with banner elements that Webflow adds late.

Go ahead, test it out! Let me know if you run into any issues.

You can find the cloneable here. More of ours live on our Webflow cloneables page.

FAQ

How do I add a dismissible banner in Webflow without cookies?

Add a div block with the attribute banner-element="banner-component" and a button inside it with banner-element="close", then paste the script right before <!-- fs-richtext-ignore --></body> in your Custom Code settings. When a visitor clicks the button, the script fades the banner out and saves a flag in sessionStorage, so no cookies are involved.

Will the banner come back if the visitor refreshes the page?

No. sessionStorage survives page reloads, so a dismissed banner stays hidden until the tab or browser is closed. MDN puts it like this: "A page session lasts as long as the tab or the browser is open, and survives over page reloads and restores." The full detail is in the MDN sessionStorage documentation.

Does a dismissed banner stay hidden in a new tab?

Usually the banner shows again. Every tab gets its own page session, and that session is only accessible in that particular tab, so a visitor who types your address or arrives from a search result in a new tab will see the banner once more. The one exception is a tab opened from a link on your site. MDN says: "Opening a page in a new tab or window creates a new session with the value of the top-level browsing context, which differs from how session cookies work." In that case the new tab starts with a copy of the original tab's session data, so the banner stays hidden.

How do I keep the banner hidden for good after it’s dismissed?

Swap sessionStorage for localStorage in the script. They share the same methods, but localStorage is kept across tabs and visits, while sessionStorage is cleared when the tab closes. That turns it into a "never show this again" banner, which is the opposite of what this post builds.

Preferred source on google logo

Share

All Posts

Gradient Background