Close menu when click detected outside

Viewed 59

I'm trying to close a menu when the user clicks outside of the element. I have tried many solutions from Stack overflow but none of them work for me. The user should be able to click on the menu button (3 dots), which then shows the menu. Then if they click outside of this, it should close each time.

https://jsfiddle.net/Lzeukhcj/1/

Here is my code and what I have tried:

Javascript

  const dots = document.querySelector(".dot-wrap");
  const popup = document.querySelector(".popup");

  dots.onclick = () => {
    popup.style.display = "block";
  }

  document.onclick = (event) => {
    let isClickInside = popup.contains(event.target);

    if (!isClickInside) {
      console.log("outside box");
      popup.style.display = 'none';
    }
  }

SCSS


.tweet-container {
  max-width: 100%;
  display: flex;
  padding-top: 10px;
  padding-bottom: 10px;
  padding-left: 5%;
  padding-right: 5%;
  border-bottom: solid 1px #f1f1f1;
}

.tweet-container-right {
  width: 100%;
  margin-left: 10px;
}

.tweet-header {
  display: flex;
  width: 100%;
  justify-content: space-between;
  align-items: center;
  z-index: 100;
}

.icon-container {
  display: flex;
  font-size: 0.8em;
}

.user-info {
  display: flex;
  align-items: center;
 

  .tweet-name {
    font-size: 15px;
    margin-right: 3px;
    color: #0f1419;
  }

  .tweet-username {
    font-size:15px;
    
    color: #526470;
  }

  .middle-dot{
    margin-left: 3px;
    margin-right: 3px;
  }

  .time {
    font-size: 15px;
    color: #526470;
  }
}

.tweet-text {
  font-size: 0.8em;
}

.verified-tick{
  margin-right: 3px;
}

.dots-popup-container {
  position: relative;

  .dots {
    width: 18px;
    fill: red;
  }

  .popup {
    background-color: white;
    position: absolute;
    right: 0;
    top: 0;
    width: 250px;
    display: none;
    /*height: 0px;*/
    transition: 2s ease;
    box-shadow: 0 0.5px 4px 0 rgba(0, 0, 0, 0.2);
    padding-top: 14px;

    .popup-option {
      display: flex;
      margin-bottom: 20px;

      p {
        color: #526470;
      }
      .popup-icon {
        width: 20px;
        margin-left: 10px;
        margin-right: 10px;
        fill: #526470;
      }
    }
  }
}

HTML

 

  <div class="tweet-container-right">
    <div class="tweet-header">
      <div class="user-info">
        <h3 class="tweet-name">Title </h3>
        
 
        <span class="middle-dot">&#183;</span>
        <p class="time">2d</p>
      </div>

      <div class="dots-popup-container">

        <div class="dot-wrap">
          <svg viewBox="0 0 24 24" aria-hidden="true" class="r-4qtqp9 r-yyyyoo r-1xvli5t r-dnmrzs r-bnwqim r-1plcrui r-lrvibr r-1hdv0qi dots">
            <g>
              <circle cx="5" cy="12" r="2"></circle>
              <circle cx="12" cy="12" r="2"></circle>
              <circle cx="19" cy="12" r="2"></circle>
            </g>
          </svg>
        </div>






        <div class="popup">
          <div class="popup-option">

            <div>
              <svg viewBox="0 0 24 24" aria-hidden="true" class="popup-icon">
                <g>
                  <path d="M12 22.75C6.072 22.75 1.25 17.928 1.25 12S6.072 1.25 12 1.25 22.75 6.072 22.75 12 17.928 22.75 12 22.75zm0-20C6.9 2.75 2.75 6.9 2.75 12S6.9 21.25 12 21.25s9.25-4.15 9.25-9.25S17.1 2.75 12 2.75z"></path>
                  <path d="M12 13.415c1.892 0 3.633.95 4.656 2.544.224.348.123.81-.226 1.035-.348.226-.812.124-1.036-.226-.747-1.162-2.016-1.855-3.395-1.855s-2.648.693-3.396 1.854c-.224.35-.688.45-1.036.225-.35-.224-.45-.688-.226-1.036 1.025-1.594 2.766-2.545 4.658-2.545zm4.216-3.957c0 .816-.662 1.478-1.478 1.478s-1.478-.66-1.478-1.478c0-.817.662-1.478 1.478-1.478s1.478.66 1.478 1.478zm-5.476 0c0 .816-.662 1.478-1.478 1.478s-1.478-.66-1.478-1.478c0-.817.662-1.478 1.478-1.478.817 0 1.478.66 1.478 1.478z"></path>
                </g>
              </svg></div>
            <p>Not interested in this tweet</p>
          </div>

          <div class="popup-option">
            <div>
              <svg viewBox="0 0 24 24" aria-hidden="true" class="popup-icon">
                <g>
                  <path d="M20.083 6.173l2.323 2.323c.293.293.768.293 1.06 0s.294-.768 0-1.06l-2.32-2.326 2.322-2.323c.293-.294.293-.77 0-1.062s-.768-.293-1.06 0L20.082 4.05 17.76 1.73c-.293-.293-.768-.293-1.06 0-.147.146-.22.338-.22.53s.072.384.22.53l2.32 2.32-2.32 2.325c-.147.146-.22.338-.22.53s.072.384.22.53c.292.293.767.293 1.06 0l2.323-2.32zM8.417 11.816c1.355 0 2.872-.15 3.84-1.256.813-.93 1.077-2.367.806-4.392-.38-2.826-2.116-4.513-4.645-4.513-2.53 0-4.267 1.687-4.646 4.513-.273 2.025-.01 3.462.805 4.393.968 1.108 2.485 1.257 3.84 1.257zm-3.16-5.448c.16-1.2.786-3.212 3.16-3.212 2.373 0 2.998 2.013 3.16 3.212.207 1.55.056 2.627-.45 3.205-.455.52-1.266.743-2.71.743s-2.256-.223-2.71-.743c-.507-.578-.658-1.656-.45-3.205zm11.44 12.867c-.88-3.525-4.283-5.988-8.28-5.988-3.998 0-7.403 2.463-8.28 5.988-.172.693-.03 1.4.395 1.94.408.522 1.04.822 1.733.822H14.57c.69 0 1.323-.3 1.73-.82.425-.54.568-1.247.396-1.942zm-1.577 1.018c-.126.16-.316.245-.55.245H2.264c-.235 0-.426-.085-.552-.246-.137-.174-.18-.412-.12-.654.71-2.855 3.517-4.85 6.824-4.85s6.113 1.994 6.824 4.85c.06.24.017.48-.12.655z"></path>
                </g>
              </svg>
            </div>
            <p>Unfollow whoever</p>
          </div>

          <div class="popup-option">
            <div>
              <svg viewBox="0 0 24 24" aria-hidden="true" class="popup-icon">
                <g>
                  <path d="M1.75 22.354c-.192 0-.384-.073-.53-.22-.293-.293-.293-.768 0-1.06L20.395 1.898c.293-.294.768-.294 1.06 0s.294.767 0 1.06L2.28 22.135c-.146.146-.338.22-.53.22zm1.716-5.577c-.134 0-.27-.036-.392-.11-.67-.413-1.07-1.13-1.07-1.917v-5.5c0-1.24 1.01-2.25 2.25-2.25H6.74l7.047-5.588c.225-.18.533-.215.792-.087.258.125.423.387.423.675v3.28c0 .415-.336.75-.75.75s-.75-.335-.75-.75V3.553L7.47 8.338c-.134.104-.298.162-.467.162h-2.75c-.413 0-.75.337-.75.75v5.5c0 .263.134.5.356.64.353.216.462.678.245 1.03-.14.23-.387.357-.64.357zm10.787 5.973c-.166 0-.33-.055-.466-.162l-4.795-3.803c-.325-.258-.38-.73-.122-1.054.258-.322.73-.38 1.054-.12l3.58 2.838v-7.013c0-.414.335-.75.75-.75s.75.336.75.75V22c0 .288-.166.55-.425.675-.104.05-.216.075-.327.075z"></path>
                </g>
              </svg> </div>
            <p>Mute whoever</p>

          </div>
          <div class="popup-option">
            <div>
              <svg viewBox="0 0 24 24" aria-hidden="true" class="popup-icon">
                <g>
                  <path d="M12 1.25C6.072 1.25 1.25 6.072 1.25 12S6.072 22.75 12 22.75 22.75 17.928 22.75 12 17.928 1.25 12 1.25zm0 1.5c2.28 0 4.368.834 5.982 2.207L4.957 17.982C3.584 16.368 2.75 14.282 2.75 12c0-5.1 4.15-9.25 9.25-9.25zm0 18.5c-2.28 0-4.368-.834-5.982-2.207L19.043 6.018c1.373 1.614 2.207 3.7 2.207 5.982 0 5.1-4.15 9.25-9.25 9.25z"></path>
                </g>
              </svg>
            </div>
            <p>Block whoever</p>
          </div>

          <div class="popup-option">
            <div>
              <svg viewBox="0 0 24 24" aria-hidden="true" class="popup-icon">
                <g>
                  <path d="M20.083 6.173l2.323 2.323c.293.293.768.293 1.06 0s.294-.768 0-1.06l-2.32-2.326 2.322-2.323c.293-.294.293-.77 0-1.062s-.768-.293-1.06 0L20.082 4.05 17.76 1.73c-.293-.293-.768-.293-1.06 0-.147.146-.22.338-.22.53s.072.384.22.53l2.32 2.32-2.32 2.325c-.147.146-.22.338-.22.53s.072.384.22.53c.292.293.767.293 1.06 0l2.323-2.32zM8.417 11.816c1.355 0 2.872-.15 3.84-1.256.813-.93 1.077-2.367.806-4.392-.38-2.826-2.116-4.513-4.645-4.513-2.53 0-4.267 1.687-4.646 4.513-.273 2.025-.01 3.462.805 4.393.968 1.108 2.485 1.257 3.84 1.257zm-3.16-5.448c.16-1.2.786-3.212 3.16-3.212 2.373 0 2.998 2.013 3.16 3.212.207 1.55.056 2.627-.45 3.205-.455.52-1.266.743-2.71.743s-2.256-.223-2.71-.743c-.507-.578-.658-1.656-.45-3.205zm11.44 12.867c-.88-3.525-4.283-5.988-8.28-5.988-3.998 0-7.403 2.463-8.28 5.988-.172.693-.03 1.4.395 1.94.408.522 1.04.822 1.733.822H14.57c.69 0 1.323-.3 1.73-.82.425-.54.568-1.247.396-1.942zm-1.577 1.018c-.126.16-.316.245-.55.245H2.264c-.235 0-.426-.085-.552-.246-.137-.174-.18-.412-.12-.654.71-2.855 3.517-4.85 6.824-4.85s6.113 1.994 6.824 4.85c.06.24.017.48-.12.655z"></path>
                </g>
              </svg>
            </div>
            <p>Mark as spoiler</p>
          </div>

        </div>
      </div>
    </div>
1 Answers

When you click the dots to open the popup, your document click event listener is checking whether the target is a child of the popup. Since the toggle is not, the modal is opened, then closed.

You can fix this by using Event.stopPropagation() to prevent this click event from being captured by the document click event listener when the dots are clicked.

Your JS should be:

window.onload = () => {
  const dots = document.querySelector(".dot-wrap");
  const popup = document.querySelector(".popup");

  dots.onclick = (e) => {
    popup.style.display = "block";
    e.stopPropagation();
  }

  document.onclick = (event) => {
      let isClickInside = popup.contains(event.target);

      if (!isClickInside) {
        console.log("outside box");
        popup.style.display = 'none';
      }
    }
}

Demo:

window.onload = () => {
  const dots = document.querySelector(".dot-wrap");
  const popup = document.querySelector(".popup");

  dots.onclick = (e) => {
    popup.style.display = "block";
    e.stopPropagation();
  }

  document.onclick = (event) => {
    let isClickInside = popup.contains(event.target);

    if (!isClickInside) {
      console.log("outside box");
      popup.style.display = 'none';
    }
  }
}
/* compiled from scss */

.tweet-container {
  max-width: 100%;
  display: flex;
  padding-top: 10px;
  padding-bottom: 10px;
  padding-left: 5%;
  padding-right: 5%;
  border-bottom: solid 1px #f1f1f1;
}

.tweet-container-right {
  width: 100%;
  margin-left: 10px;
}

.tweet-header {
  display: flex;
  width: 100%;
  justify-content: space-between;
  align-items: center;
  z-index: 100;
}

.icon-container {
  display: flex;
  font-size: 0.8em;
}

.user-info {
  display: flex;
  align-items: center;
}

.user-info .tweet-name {
  font-size: 15px;
  margin-right: 3px;
  color: #0f1419;
}

.user-info .tweet-username {
  font-size: 15px;
  color: #526470;
}

.user-info .middle-dot {
  margin-left: 3px;
  margin-right: 3px;
}

.user-info .time {
  font-size: 15px;
  color: #526470;
}

.tweet-text {
  font-size: 0.8em;
}

.verified-tick {
  margin-right: 3px;
}

.dots-popup-container {
  position: relative;
}

.dots-popup-container .dots {
  width: 18px;
  fill: red;
}

.dots-popup-container .popup {
  background-color: white;
  position: absolute;
  right: 0;
  top: 0;
  width: 250px;
  display: none;
  /*height: 0px;*/
  transition: 2s ease;
  box-shadow: 0 0.5px 4px 0 rgba(0, 0, 0, 0.2);
  padding-top: 14px;
}

.dots-popup-container .popup .popup-option {
  display: flex;
  margin-bottom: 20px;
}

.dots-popup-container .popup .popup-option p {
  color: #526470;
}

.dots-popup-container .popup .popup-option .popup-icon {
  width: 20px;
  margin-left: 10px;
  margin-right: 10px;
  fill: #526470;
}
<div class="tweet-container">
  <div class="tweet-container-right">
    <div class="tweet-header">
      <div class="user-info">
        <h3 class="tweet-name">Title </h3>
        <span class="middle-dot">&#183;</span>
        <p class="time">2d</p>
      </div>
      <div class="dots-popup-container">
        <div class="dot-wrap">
          <svg viewBox="0 0 24 24" aria-hidden="true" class="r-4qtqp9 r-yyyyoo r-1xvli5t r-dnmrzs r-bnwqim r-1plcrui r-lrvibr r-1hdv0qi dots">
            <g>
              <circle cx="5" cy="12" r="2"></circle>
              <circle cx="12" cy="12" r="2"></circle>
              <circle cx="19" cy="12" r="2"></circle>
            </g>
          </svg>
        </div>
        <div class="popup">
          <div class="popup-option">
            <div>
              <svg viewBox="0 0 24 24" aria-hidden="true" class="popup-icon">
                <g>
                  <path d="M12 22.75C6.072 22.75 1.25 17.928 1.25 12S6.072 1.25 12 1.25 22.75 6.072 22.75 12 17.928 22.75 12 22.75zm0-20C6.9 2.75 2.75 6.9 2.75 12S6.9 21.25 12 21.25s9.25-4.15 9.25-9.25S17.1 2.75 12 2.75z"></path>
                  <path d="M12 13.415c1.892 0 3.633.95 4.656 2.544.224.348.123.81-.226 1.035-.348.226-.812.124-1.036-.226-.747-1.162-2.016-1.855-3.395-1.855s-2.648.693-3.396 1.854c-.224.35-.688.45-1.036.225-.35-.224-.45-.688-.226-1.036 1.025-1.594 2.766-2.545 4.658-2.545zm4.216-3.957c0 .816-.662 1.478-1.478 1.478s-1.478-.66-1.478-1.478c0-.817.662-1.478 1.478-1.478s1.478.66 1.478 1.478zm-5.476 0c0 .816-.662 1.478-1.478 1.478s-1.478-.66-1.478-1.478c0-.817.662-1.478 1.478-1.478.817 0 1.478.66 1.478 1.478z"></path>
                </g>
              </svg></div>
            <p>Not interested in this tweet</p>
          </div>
          <div class="popup-option">
            <div>
              <svg viewBox="0 0 24 24" aria-hidden="true" class="popup-icon">
                <g>
                  <path d="M20.083 6.173l2.323 2.323c.293.293.768.293 1.06 0s.294-.768 0-1.06l-2.32-2.326 2.322-2.323c.293-.294.293-.77 0-1.062s-.768-.293-1.06 0L20.082 4.05 17.76 1.73c-.293-.293-.768-.293-1.06 0-.147.146-.22.338-.22.53s.072.384.22.53l2.32 2.32-2.32 2.325c-.147.146-.22.338-.22.53s.072.384.22.53c.292.293.767.293 1.06 0l2.323-2.32zM8.417 11.816c1.355 0 2.872-.15 3.84-1.256.813-.93 1.077-2.367.806-4.392-.38-2.826-2.116-4.513-4.645-4.513-2.53 0-4.267 1.687-4.646 4.513-.273 2.025-.01 3.462.805 4.393.968 1.108 2.485 1.257 3.84 1.257zm-3.16-5.448c.16-1.2.786-3.212 3.16-3.212 2.373 0 2.998 2.013 3.16 3.212.207 1.55.056 2.627-.45 3.205-.455.52-1.266.743-2.71.743s-2.256-.223-2.71-.743c-.507-.578-.658-1.656-.45-3.205zm11.44 12.867c-.88-3.525-4.283-5.988-8.28-5.988-3.998 0-7.403 2.463-8.28 5.988-.172.693-.03 1.4.395 1.94.408.522 1.04.822 1.733.822H14.57c.69 0 1.323-.3 1.73-.82.425-.54.568-1.247.396-1.942zm-1.577 1.018c-.126.16-.316.245-.55.245H2.264c-.235 0-.426-.085-.552-.246-.137-.174-.18-.412-.12-.654.71-2.855 3.517-4.85 6.824-4.85s6.113 1.994 6.824 4.85c.06.24.017.48-.12.655z"></path>
                </g>
              </svg>
            </div>
            <p>Unfollow whoever</p>
          </div>

          <div class="popup-option">
            <div>
              <svg viewBox="0 0 24 24" aria-hidden="true" class="popup-icon">
                <g>
                  <path d="M1.75 22.354c-.192 0-.384-.073-.53-.22-.293-.293-.293-.768 0-1.06L20.395 1.898c.293-.294.768-.294 1.06 0s.294.767 0 1.06L2.28 22.135c-.146.146-.338.22-.53.22zm1.716-5.577c-.134 0-.27-.036-.392-.11-.67-.413-1.07-1.13-1.07-1.917v-5.5c0-1.24 1.01-2.25 2.25-2.25H6.74l7.047-5.588c.225-.18.533-.215.792-.087.258.125.423.387.423.675v3.28c0 .415-.336.75-.75.75s-.75-.335-.75-.75V3.553L7.47 8.338c-.134.104-.298.162-.467.162h-2.75c-.413 0-.75.337-.75.75v5.5c0 .263.134.5.356.64.353.216.462.678.245 1.03-.14.23-.387.357-.64.357zm10.787 5.973c-.166 0-.33-.055-.466-.162l-4.795-3.803c-.325-.258-.38-.73-.122-1.054.258-.322.73-.38 1.054-.12l3.58 2.838v-7.013c0-.414.335-.75.75-.75s.75.336.75.75V22c0 .288-.166.55-.425.675-.104.05-.216.075-.327.075z"></path>
                </g>
              </svg> </div>
            <p>Mute whoever</p>
          </div>
          <div class="popup-option">
            <div>
              <svg viewBox="0 0 24 24" aria-hidden="true" class="popup-icon">
                <g>
                  <path d="M12 1.25C6.072 1.25 1.25 6.072 1.25 12S6.072 22.75 12 22.75 22.75 17.928 22.75 12 17.928 1.25 12 1.25zm0 1.5c2.28 0 4.368.834 5.982 2.207L4.957 17.982C3.584 16.368 2.75 14.282 2.75 12c0-5.1 4.15-9.25 9.25-9.25zm0 18.5c-2.28 0-4.368-.834-5.982-2.207L19.043 6.018c1.373 1.614 2.207 3.7 2.207 5.982 0 5.1-4.15 9.25-9.25 9.25z"></path>
                </g>
              </svg>
            </div>
            <p>Block whoever</p>
          </div>
          <div class="popup-option">
            <div>
              <svg viewBox="0 0 24 24" aria-hidden="true" class="popup-icon">
                <g>
                  <path d="M20.083 6.173l2.323 2.323c.293.293.768.293 1.06 0s.294-.768 0-1.06l-2.32-2.326 2.322-2.323c.293-.294.293-.77 0-1.062s-.768-.293-1.06 0L20.082 4.05 17.76 1.73c-.293-.293-.768-.293-1.06 0-.147.146-.22.338-.22.53s.072.384.22.53l2.32 2.32-2.32 2.325c-.147.146-.22.338-.22.53s.072.384.22.53c.292.293.767.293 1.06 0l2.323-2.32zM8.417 11.816c1.355 0 2.872-.15 3.84-1.256.813-.93 1.077-2.367.806-4.392-.38-2.826-2.116-4.513-4.645-4.513-2.53 0-4.267 1.687-4.646 4.513-.273 2.025-.01 3.462.805 4.393.968 1.108 2.485 1.257 3.84 1.257zm-3.16-5.448c.16-1.2.786-3.212 3.16-3.212 2.373 0 2.998 2.013 3.16 3.212.207 1.55.056 2.627-.45 3.205-.455.52-1.266.743-2.71.743s-2.256-.223-2.71-.743c-.507-.578-.658-1.656-.45-3.205zm11.44 12.867c-.88-3.525-4.283-5.988-8.28-5.988-3.998 0-7.403 2.463-8.28 5.988-.172.693-.03 1.4.395 1.94.408.522 1.04.822 1.733.822H14.57c.69 0 1.323-.3 1.73-.82.425-.54.568-1.247.396-1.942zm-1.577 1.018c-.126.16-.316.245-.55.245H2.264c-.235 0-.426-.085-.552-.246-.137-.174-.18-.412-.12-.654.71-2.855 3.517-4.85 6.824-4.85s6.113 1.994 6.824 4.85c.06.24.017.48-.12.655z"></path>
                </g>
              </svg>
            </div>
            <p>Mark as spoiler</p>
          </div>
        </div>
      </div>
    </div>

Related