0

I'd like to be able to place a dropdown via CSS anywhere in my HTML prototype. This means I need to be able to place multiple dropdowns anywhere on the page.

Right now I use this to create a single dropdown:

<div class="dropdown">
  <button onclick="myFunction()" class="dropbtn">Click here 01 </button>
    <div id="myDropdown" class="dropdown-content">
       <a href="#">link</a>
       <a href="#">link</a>
       <a href="#">link</a>
    </div>
</div> 

function myFunction() {
document.getElementById("myDropdown").classList.toggle("show");
}

window.onclick = function(event) {
if (!event.target.matches('.dropbtn')) {

var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
  var openDropdown = dropdowns[i];
  if (openDropdown.classList.contains('show')) {
    openDropdown.classList.remove('show');
  }
}

} }

How do I create multiple dropdowns using the same Javascript?

Here is a demo that does not work: https://codepen.io/db13/pen/pLGRwr

6
  • 2
    Please save the demo and share the URL. Commented Apr 10, 2018 at 4:39
  • I just saved the codepen demo Commented Apr 10, 2018 at 4:40
  • I'm sorry, now the demo has been updated Commented Apr 10, 2018 at 4:42
  • Is that ok if you get a jQuery code?? Commented Apr 10, 2018 at 4:47
  • I like how the dropdown is pure HTML/CSS/JS without JQuery, but if you have a JQuery solution lets hear it! What are you thinking? Commented Apr 10, 2018 at 4:49

2 Answers 2

3

Pure CSS Way

This approach is with pure CSS only

#demo {
  margin: 30px 0 50px 0;
  font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
}

#demo .wrapper {
  display: inline-block;
  width: 180px;
  margin: 0 10px 0 0;
  height: 20px;
  position: relative;
}

#demo .parent {
  height: 100%;
  width: 100%;
  display: block;
  cursor: pointer;
  line-height: 30px;
  height: 30px;
  border-radius: 5px;
  background: #F9F9F9;
  border: 1px solid #AAA;
  border-bottom: 1px solid #777;
  color: #282D31;
  font-weight: bold;
  z-index: 2;
  position: relative;
  -webkit-transition: border-radius .1s linear, background .1s linear, z-index 0s linear;
  -webkit-transition-delay: .8s;
  text-align: center;
}

#demo .parent:hover,
#demo .content:hover~.parent {
  background: #fff;
  -webkit-transition-delay: 0s, 0s, 0s;
}

#demo .content:hover~.parent {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  z-index: 0;
}

#demo .content {
  position: absolute;
  top: 0;
  display: block;
  z-index: 1;
  height: 0;
  width: 180px;
  padding-top: 30px;
  -webkit-transition: height .5s ease;
  -webkit-transition-delay: .4s;
  border: 1px solid #777;
  border-radius: 5px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .4);
}

#demo .wrapper:active .content {
  height: 123px;
  z-index: 3;
  -webkit-transition-delay: 0s;
}

#demo .content:hover {
  height: 123px;
  z-index: 3;
  -webkit-transition-delay: 0s;
}

#demo .content ul {
  background: #fff;
  margin: 0;
  padding: 0;
  overflow: hidden;
  height: 100%;
  border-bottom-left-radius: 5px;
  border-bottom-right-radius: 5px;
}

#demo .content ul a {
  text-decoration: none;
}

#demo .content li:hover {
  background: #eee;
  color: #333;
}

#demo .content li {
  list-style: none;
  text-align: left;
  color: #888;
  font-size: 14px;
  line-height: 30px;
  height: 30px;
  padding-left: 10px;
  border-top: 1px solid #ccc;
}

#demo .content li:last-of-type {
  border-bottom-left-radius: 5px;
  border-bottom-right-radius: 5px;
}
<div id="demo">
  <div class="wrapper">
    <div class="content">
      <ul>
        <a href="#">
          <li>Parent 1 Element 1</li>
        </a>
        <a href="#">
          <li>Parent 1 Parent 1 Element 1</li>
        </a>
        <a href="#">
          <li>Parent 1 Element 1</li>
        </a>
        <a href="#">
          <li>Parent 1 Element 1</li>
        </a>
      </ul>
    </div>
    <div class="parent">Button 1</div>
  </div>

  <div class="wrapper">
    <div class="content">
      <ul>
        <a href="#">
          <li>Parent 2 Element 1</li>
        </a>
        <a href="#">
          <li>Parent 2 Element 2</li>
        </a>
        <a href="#">
          <li>Parent 2 Element 3</li>
        </a>
        <a href="#">
          <li>Parent 2 Element 4</li>
        </a>
      </ul>
    </div>
    <div class="parent">Button 2</div>
  </div>

Vanilla JavaScript

Approach with vanilla javascript

Reference from my own GitHub repository here

function fadeIn(el) {
  el.style.opacity = 0;
  el.style.display = "block";

  (function fade() {
    var val = parseFloat(el.style.opacity);
    if (!((val += 0.1) >= 1.1)) {
      el.style.opacity = val;
      requestAnimationFrame(fade);
    }
  }());
}

function fadeOut(el) {
  (function fade() {
    var val = parseFloat(el.style.opacity);
    if ((val -= 0.1) == 0) {
      el.style.opacity = 0;
      el.style.display = "none";
    } else {
      el.style.opacity = val;
      requestAnimationFrame(fade);
    }
  }());
}

// Initialise all the required variables
var btn = document.querySelectorAll(".btn");

/*
 *	Button click event listeners
 *	Keeps track of the button click.
 */
btn.forEach(function(btn) {
  btn.addEventListener("click", function(e) {
    e.stopPropagation();
    var sibling = btn.nextElementSibling,
      firstVisible = document.querySelector('.visible'),
      dropDown;

    /*
     * Remove the visible class if an element is already in the DOM
     */
    if (firstVisible) {
      fadeOut(firstVisible);
      firstVisible.classList.remove("visible");
    }

    if (!sibling.classList.contains("visible")) {
      fadeIn(sibling);
      sibling.classList.add("visible");
    } else {
      fadeOut(sibling);
      sibling.classList.remove("visible");
    }
  });
});

document.addEventListener("click", function() {
  var visible = document.querySelector(".visible");

  if (visible) {
    fadeOut(visible);
    visible.classList.remove("visible");
  }
});
.btn {
  outline: none;
  border: none;
  padding: 10px 20px;
  cursor: pointer;
  background-color: #e0e0e0;
  color: #7b7b7b;
  width: 150px;
  box-shadow: 2px 2px 4px 0px rgba(0, 0, 0, .18);
  font-weight: bold;
  margin-bottom: 20px;
  transition: all .3s ease-in-out;
}

.btn:active {
  box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px 1px rgba(0, 0, 0, .2);
  background-color: rgba(158, 158, 158, .4);
}

.btn-dropdown {
  padding: 0px;
  margin: 0px;
  list-style: none;
  background-color: #fff;
  position: absolute;
  left: 0px;
  top: 30px;
  box-shadow: 2px 2px 4px 0px rgba(0, 0, 0, .18);
  min-width: 200px;
  border: 1px solid #ddd;
  text-align: initial;
  max-height: 210px;
  overflow: auto;
  display: none;
  z-index: 100;
}

.btn-dropdown li {
  padding: 6px;
  margin: 0px;
  border-bottom: 1px solid #ddd;
  cursor: pointer;
}

.btn-dropdown li:hover {
  background-color: #ddd;
}

.btn-dropdown li:last-child {
  border-bottom: none;
}

.dropdown {
  position: relative;
  display: inline;
}
<div>
  <div class="dropdown">
    <button class="btn">First Color</button>
    <ul class="btn-dropdown">
      <li>Brown</li>
      <li>Red</li>
      <li>Orange</li>
      <li>Yellow</li>
      <li>Green</li>
      <li>Blue</li>
      <li>Violet</li>
      <li>Grey</li>
      <li>White</li>
    </ul>
  </div>

  <div class="dropdown">
    <button class="btn">Second Color</button>
    <ul class="btn-dropdown">
      <li>Brown</li>
      <li>Red</li>
      <li>Orange</li>
      <li>Yellow</li>
      <li>Green</li>
      <li>Blue</li>
      <li>Violet</li>
      <li>Grey</li>
      <li>White</li>
    </ul>
  </div>
</div>

jQuery Way

Approach with jQuery you need an extra plugin (Sorry about that)

Reference from my own question in the past Drop down list items still clickable when the opacity is zero

$(".btn").on('click', function(e) {
  e.stopPropagation();
  var $dropdown = $(this).siblings().fadeToggle(); // toggle this dropdown
  $('.dropdown .btn-dropdown').not($dropdown).fadeOut(); // hide other dropdowns
});

$(document).on('click', function(e) {
  $('.dropdown .btn-dropdown').fadeOut(); // hide all dropdowns
});
.btn {
  outline: none;
  border: none;
  padding: 10px 20px;
  cursor: pointer;
  background-color: #eee;
  color: #7b7b7b;
  width: 150px;
  box-shadow: 4px 4px 6px 0px rgba(0, 0, 0, .16);
  font-weight: bold;
  margin-bottom: 20px;
}

.dropdown {
  position: relative;
  display: inline;
}

.btn-dropdown {
  padding: 0px;
  margin: 0px;
  list-style: none;
  background-color: #fff;
  position: absolute;
  left: 0px;
  top: 30px;
  box-shadow: 4px 4px 6px 0px rgba(0, 0, 0, .16);
  min-width: 200px;
  border: 1px solid #ddd;
  text-align: initial;
  max-height: 210px;
  overflow: auto;
  display: none;
  z-index: 100;
}

.btn-dropdown li {
  padding: 6px;
  margin: 0px;
  border-bottom: 1px solid #ddd;
  cursor: pointer;
}

.btn-dropdown li:hover {
  background-color: #ddd;
}

.btn-dropdown li:last-child {
  border-bottom: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="dropdown">
  <button class="btn first">Select something</button>
  <ul class="btn-dropdown">
    <li>First</li>
    <li>Second</li>
    <li>Third</li>
    <li>Fourth</li>
  </ul>
</div>

<div class="dropdown">
  <button class="btn first">Select something</button>
  <ul class="btn-dropdown">
    <li>Black</li>
    <li>Brown</li>
    <li>Red</li>
    <li>Orange</li>
  </ul>
</div>

Sign up to request clarification or add additional context in comments.

Comments

1

Part of your issue is that ID's should be unique. Your function is calling effectively the first #myDropdown each time.

You can modify your function to pass this as a context target to it, and grab the dropdown dynamically using the class name.

Check out this example: CodePen Demo

Change your onclick to this:

 <button onclick="myFunction(this)" class="dropbtn">Click here 01 </button>

And change myFunction to this:

var myFunction = function(target) {
   target.parentNode.querySelector('.dropdown-content').classList.toggle("show");
}

15 Comments

This just worked for a second but then it stopped working. Can you save the codepen?
Oh sorry about that, I accidentally saved over the selector when I pasted into the wrong pen. Fixed!
You shouldn't need to target the class since ID selectors have a specificity of 100, and classes only have a specificity of 10. However If you absolutely need the class for some reason, just add it to the selector. #myDropdown2.dropdown-content { /* CSS */ }
You may want to consider reading up on the Specifics of CSS Specificity, which will better explain it than I can in a comment thread
My pleasure, glad to help!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.