A 'site message banner' component that can display multiple messages, animates their closing, and remembers closed messages via localStorage

by philw_

HTML

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/1.4.6/tailwind.min.css">
<script src="https://cdn.jsdelivr.net/gh/ctidigital/outline.js@1.3.0/outline.js"></script>
<script
  src="https://cdn.jsdelivr.net/npm/alpinejs@2.3.3/dist/alpine.js"
  integrity="sha256-YMtt6o4gwAMeWbjhX1r2n/ZgaCCA7BEKCRsLVN+qeDA="
  crossorigin="anonymous"
></script>

<div x-data="messageBannerData()">
  <!-- 
    The messages would come from a CMS that would supply the hashes
    used in the x-ref values and x-show functions. The hashes represent
    the content of the message and serve as a unique ID.
  -->
  <div
    x-ref="20482A0"
    x-show="isVisible('20482A0')"
    class="bg-red-200 px-8 duration-200 ease-in transition-all overflow-hidden"
  >
    <div class="py-4 flex space-x-3">
      <div class="w-6 text-red-800" data-feather="alert-triangle"></div>
      <p class="flex-grow" data-message-text>Pre-closed message</p>
      <button
        class="duration-100 ease-in-out focus:scale-110 hover:scale-110 transform transition-transform"
        @click="close('20482A0')"
        aria-label="Close"
      >
        <div data-feather="x"></div>
      </button>
    </div>
  </div>

  <div
    x-ref="36EFA59"
    x-show="isVisible('36EFA59')"
    class="bg-red-200 px-8 duration-200 ease-in transition-all overflow-hidden"
  >
    <div class="py-4 flex space-x-3">
      <div class="w-6 text-red-800" data-feather="alert-triangle"></div>
      <p class="flex-grow" data-message-text>Message banner one</p>
      <button
        class="duration-100 ease-in-out focus:scale-110 hover:scale-110 transform transition-transform"
        @click="close('36EFA59')"
        aria-label="Close"
      >
        <div data-feather="x"></div>
      </button>
    </div>
  </div>

  <div
    x-ref="135C4C1"
    x-show="isVisible('135C4C1')"
    class="bg-green-200 px-8 duration-200 ease-in transition-all overflow-hidden"
  >
    <div class="py-4 flex space-x-3">
      <div class="w-6...

JavaScript

function messageBannerData() {
  return {
    closedMessages: {
      ...JSON.parse(window.localStorage.getItem('closedMessages')),
      // We 'prehide' one message, perhaps based on server-side logic:
      '20482A0': false,
    },
    close(hash) {
      const elem = this.$refs[hash];
      elem.style.height = elem.scrollHeight + 'px';

      window.setTimeout(() => {
        elem.style.height = '0';
      }, 50);

      elem.addEventListener('transitionend', () => {
        this.closedMessages[hash] = false;
        window.localStorage.setItem('closedMessages', JSON.stringify(this.closedMessages));
      });
    },
    isVisible(hash) {
      return !this.closedMessages.hasOwnProperty(hash);
    },
    resetDemo() {
      if (confirm("This will clear the localStorage and reset the demo")) {
        window.localStorage.removeItem('closedMessages');
        
        window.setTimeout(() => {
          window.location.reload(true);
        }, 0);
      }
    }
  }
}