Info Overlay

Clicking the ‘.info-toggle’ element will display (or hide) the ‘.info-overlay’ element.
Keyboard accessible!

  • The ‘disable’ function sets all links within the overlay element to ‘tabindex = “-1″‘ on page load. When the overlay is toggled, all links are set to ‘tabindex = “0”‘. This prevents them from being focused while the overlay is hidden when using the user presses the ‘Tab’ key to browse the website.
  • Pressing the ‘Escape’ key will hide the overlay.
  • Clicking anywhere outside of the overlay will hide the overlay.
  • Scrolling will hide the overlay — disabled by default.

CodePen

JavaScript

// **************************************************
//  Info Overlay
//  Toggle
// **************************************************
const infoOverlayToggle = document.querySelector('.info-toggle');
const infoOverlay = document.querySelector('.info-overlay');
const infoOverlayLink = document.querySelectorAll('.info-overlay a');

const toggleInfo = () => {
    // show
    const show = () => {
        infoOverlay.classList.toggle('show');
    };

    // hide
    const hide = () => {
        infoOverlay.classList.remove('show');
    };

    // set all link elements to tabindex="0"
    const enable = () => {
        infoOverlayLink.forEach((element) => {
            element.setAttribute('tabindex', '0');
        });
    };

    // set all link elements to tabindex="-1"
    const disable = () => {
        infoOverlayLink.forEach((element) => {
            element.setAttribute('tabindex', '-1');
        });
    };
    disable(); // run this on page load

    // focus the overlay 
    const focusOverlay = () => {
        infoOverlay.setAttribute('tabindex', '0');
        infoOverlay.focus();
        infoOverlayToggle.classList.add('clicked'); // mimics the toggle's hover/focus CSS
    };

    // focus the toggle 
    const focusToggle = () => {
        infoOverlay.setAttribute('tabindex', '-1');
        infoOverlayToggle.focus();
        infoOverlayToggle.classList.remove('clicked');
    };

    // all functions to 'open' the menu
    const open = () => {
        show();
        enable();
        focusOverlay();
    }

    // all functions to 'close' the menu
    const close = () => {
        hide();
        disable();
        focusToggle();
    }

    // toggle is clicked
    infoOverlayToggle.addEventListener('click', () => {
        if (!infoOverlay.classList.contains('show')) {
            open();
        } else {
            close();
        };
    });

    // hide when 'Escape' key is pressed
    document.addEventListener('keydown', (event) => {
        if ((infoOverlay.classList.contains('show')) && (event.keyCode == 27)) {
            close();
        }
    });

    // hide when user clicks anywhere outside of the overlay
    document.addEventListener('click', (event) => {
        if (infoOverlay.classList.contains('show')) {
            let targetElement = event.target;

            do {
                if (targetElement == infoOverlay || targetElement == infoOverlayToggle) {
                    return;
                }
                targetElement = targetElement.parentNode;
            } while (targetElement);

            close();
        };
    });

    // hide when a user scrolls up/down
    // DISABLED
    // document.addEventListener('scroll', () => {
    //     close();
    // });
};
toggleInfo();

HTML

<div class="info">
    <a href="#" class="info-toggle" aria-label="Contact Information"><i class="fa-solid fa-comment"></i></a>
    <div class="info-overlay">
        <p>Email Us:<br><a href="mailto:email@me.com">email@me.com</a></p>
        <p>Call Us:<br><a href="tel:15558299982">(555) 829-9982</a></p>
    </div>
</div>

CSS

// **************************************************
//  Info
// **************************************************

body {
  font-family: Arial, sans-serif;
}

.info {
  display: flex;
  justify-content: center;
  position: relative;
  overflow: visible;

  .info-toggle {
    display: block;
    color: rebeccapurple;
    font-size: 5rem;
    text-decoration: none;

    &:hover,
    &:focus,
    &.clicked {
      color: blueviolet;
    }
  }

  .info-overlay {
    visibility: hidden;
    opacity: 0;
    z-index: -1;
    background: whitesmoke;
    box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.3);
    position: absolute;
    inset: 90px auto auto auto;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 1em 2.5em;
    min-height: 140px;
    z-index: 9999;

    &.show {
      visibility: visible;
      opacity: 1;
      z-index: 9999;
      transition: opacity 0.3s;
    }

    p {
      color: #000;
      font-size: 0.9rem;
      line-height: 1rem;

      a {
        color: steelblue;
        font-weight: 600;
        text-decoration: none;
      }
    }
  }
}

CodePen