Search code examples
cssz-index

Fix z-index with overlapping dropdowns


I'm having a problem in a project I'm working on with z-index.

I have several components which all have a dropdown. The problem I have is that the dropdown from the first components goes under the dropdown button of the second and this makes the content partially hidden.

I basically need the first dropdown to have the highest z-index. But as I'm styling them all the same, they all have the same z-index.

I'd like to solve this without JavaScript where I have to dynamically change the z-index or the solution with flexbox that's attached to the code snippet.

const dropdowns = document.querySelectorAll('.app-item-dropdown');

dropdowns.forEach((item) => {
  item.querySelector('button').addEventListener('click', function() {
    this.nextElementSibling.parentNode.classList.toggle('expanded')
  })
})
:root {
  --z1: 1;
  --z2: 2;
  --z3: 3;
  --z4: 4;
  --z5: 5;
}

html {
  box-sizing: border-box; 
}
*, *:after, *:before {
  box-sizing: inherit;
}

body {
  background: lightgrey;
  text-align: center;
}

ul {
  margin: 0; padding: 0; list-style: none;
}

.container {
  max-width: 960px; margin: 0 auto; border: 1px solid red;
  padding: 24px;
}

.solution {
  display: flex;
  flex-direction: column-reverse;
}

.app-item {
  border: 1px solid yellow;
  min-height: 150px;
  background: grey;
  position: relative;
  margin: 24px;
}

.app-item-dropdown {
  
  position: absolute;
  width: 272px;
  top: 16px;
  right: 16px;
  background: white;
  z-index: var(--z2);
}

.app-item-dropdown ul {
  display: none;
  position:relative;
  z-index: var(--z4);
}

.app-item-dropdown ul li {
  padding: 4px 8px;
}

.app-item-dropdown.expanded ul{
  display: block;
}

.lightblue {
  background: lightblue;
}

.lightsalmon {
  background: lightsalmon; 
}
<div id="wrapper" class="container problem">
  <div class="app-item">
    <h2>1</h2>
    <div class="app-item-dropdown">
      <button>click</button>
      <div class="box">
        <ul>
          <li>hello</li>
          <li>hello</li>
          <li>hellohello</li>
          <li>hello</li>
          <li>hello</li>
          <li>hello</li>
          <li>hehellohellollo</li>
          <li>hello</li>
          <li>helhellolo</li>
          <li>hello</li>
        </ul>
      </div>
    </div>
  </div>
  
  <div class="app-item">
    <h2>2</h2>
    <div class="app-item-dropdown lightblue">
      <button>click</button>
      <div class="box">
        <ul>
          <li>hello</li>
          <li>hello</li>
          <li>hellohello</li>
          <li>hello</li>
          <li>hello</li>
          <li>hello</li>
          <li>hehellohellollo</li>
          <li>hello</li>
          <li>helhellolo</li>
          <li>hello</li>
        </ul>
      </div>
    </div>
  </div>
  <div class="app-item">
    <h2>3</h2>
    <div class="app-item-dropdown lightsalmon">
      <button>click</button>
      <div class="box">
        <ul>
          <li>hello</li>
          <li>hello</li>
          <li>hellohello</li>
          <li>hello</li>
          <li>hello</li>
          <li>hello</li>
          <li>hehellohellollo</li>
          <li>hello</li>
          <li>helhellolo</li>
          <li>hello</li>
        </ul>
      </div>
    </div>
  </div>
</div>


<hr>
<h1>Solution</h1>
<h2>With <code>flex-direction: column-reverse</code> </h2>


<div id="wrapper2" class="container solution">
  <div class="app-item">
    <h2>1</h2>
    <div class="app-item-dropdown">
      <button>click</button>
      <div class="box">
        <ul>
          <li>hello</li>
          <li>hello</li>
          <li>hellohello</li>
          <li>hello</li>
          <li>hello</li>
          <li>hello</li>
          <li>hehellohellollo</li>
          <li>hello</li>
          <li>helhellolo</li>
          <li>hello</li>
        </ul>
      </div>
    </div>
  </div>
  
  <div class="app-item">
    <h2>2</h2>
    <div class="app-item-dropdown lightblue">
      <button>click</button>
      <div class="box">
        <ul>
          <li>hello</li>
          <li>hello</li>
          <li>hellohello</li>
          <li>hello</li>
          <li>hello</li>
          <li>hello</li>
          <li>hehellohellollo</li>
          <li>hello</li>
          <li>helhellolo</li>
          <li>hello</li>
        </ul>
      </div>
    </div>
  </div>
  <div class="app-item">
    <h2>3</h2>
    <div class="app-item-dropdown lightsalmon">
      <button>click</button>
      <div class="box">
        <ul>
          <li>hello</li>
          <li>hello</li>
          <li>hellohello</li>
          <li>hello</li>
          <li>hello</li>
          <li>hello</li>
          <li>hehellohellollo</li>
          <li>hello</li>
          <li>helhellolo</li>
          <li>hello</li>
        </ul>
      </div>
    </div>
  </div>
</div>


Solution

  • Set the z-index of the class you're adding on click higher than the z-index of the existing elements.

    const dropdowns = document.querySelectorAll('.app-item-dropdown');
    
    dropdowns.forEach((item) => {
      item.querySelector('button').addEventListener('click', function() {
        this.nextElementSibling.parentNode.classList.toggle('expanded')
      })
    })
    :root {
      --z1: 1;
      --z2: 2;
      --z3: 3;
      --z4: 4;
      --z5: 5;
    }
    
    html {
      box-sizing: border-box; 
    }
    *, *:after, *:before {
      box-sizing: inherit;
    }
    
    body {
      background: lightgrey;
      text-align: center;
    }
    
    ul {
      margin: 0; padding: 0; list-style: none;
    }
    
    .container {
      max-width: 960px; margin: 0 auto; border: 1px solid red;
      padding: 24px;
    }
    
    .solution {
      display: flex;
      flex-direction: column-reverse;
    }
    
    .app-item {
      border: 1px solid yellow;
      min-height: 150px;
      background: grey;
      position: relative;
      margin: 24px;
    }
    
    .app-item-dropdown {
      
      position: absolute;
      width: 272px;
      top: 16px;
      right: 16px;
      background: white;
      z-index: var(--z2);
    }
    
    .app-item-dropdown ul {
      display: none;
      position:relative;
      z-index: var(--z4);
    }
    
    .app-item-dropdown ul li {
      padding: 4px 8px;
    }
    
    .app-item-dropdown.expanded ul{
      display: block;
    }
    
    .lightblue {
      background: lightblue;
    }
    
    .lightsalmon {
      background: lightsalmon; 
    }
    
    .expanded {
        z-index: 5;
    }
    <div id="wrapper" class="container problem">
      <div class="app-item">
        <h2>1</h2>
        <div class="app-item-dropdown">
          <button>click</button>
          <div class="box">
            <ul>
              <li>hello</li>
              <li>hello</li>
              <li>hellohello</li>
              <li>hello</li>
              <li>hello</li>
              <li>hello</li>
              <li>hehellohellollo</li>
              <li>hello</li>
              <li>helhellolo</li>
              <li>hello</li>
            </ul>
          </div>
        </div>
      </div>
      
      <div class="app-item">
        <h2>2</h2>
        <div class="app-item-dropdown lightblue">
          <button>click</button>
          <div class="box">
            <ul>
              <li>hello</li>
              <li>hello</li>
              <li>hellohello</li>
              <li>hello</li>
              <li>hello</li>
              <li>hello</li>
              <li>hehellohellollo</li>
              <li>hello</li>
              <li>helhellolo</li>
              <li>hello</li>
            </ul>
          </div>
        </div>
      </div>
      <div class="app-item">
        <h2>3</h2>
        <div class="app-item-dropdown lightsalmon">
          <button>click</button>
          <div class="box">
            <ul>
              <li>hello</li>
              <li>hello</li>
              <li>hellohello</li>
              <li>hello</li>
              <li>hello</li>
              <li>hello</li>
              <li>hehellohellollo</li>
              <li>hello</li>
              <li>helhellolo</li>
              <li>hello</li>
            </ul>
          </div>
        </div>
      </div>
    </div>
    
    
    <hr>
    <h1>Solution</h1>
    <h2>With <code>flex-direction: column-reverse</code> </h2>
    
    
    <div id="wrapper2" class="container solution">
      <div class="app-item">
        <h2>1</h2>
        <div class="app-item-dropdown">
          <button>click</button>
          <div class="box">
            <ul>
              <li>hello</li>
              <li>hello</li>
              <li>hellohello</li>
              <li>hello</li>
              <li>hello</li>
              <li>hello</li>
              <li>hehellohellollo</li>
              <li>hello</li>
              <li>helhellolo</li>
              <li>hello</li>
            </ul>
          </div>
        </div>
      </div>
      
      <div class="app-item">
        <h2>2</h2>
        <div class="app-item-dropdown lightblue">
          <button>click</button>
          <div class="box">
            <ul>
              <li>hello</li>
              <li>hello</li>
              <li>hellohello</li>
              <li>hello</li>
              <li>hello</li>
              <li>hello</li>
              <li>hehellohellollo</li>
              <li>hello</li>
              <li>helhellolo</li>
              <li>hello</li>
            </ul>
          </div>
        </div>
      </div>
      <div class="app-item">
        <h2>3</h2>
        <div class="app-item-dropdown lightsalmon">
          <button>click</button>
          <div class="box">
            <ul>
              <li>hello</li>
              <li>hello</li>
              <li>hellohello</li>
              <li>hello</li>
              <li>hello</li>
              <li>hello</li>
              <li>hehellohellollo</li>
              <li>hello</li>
              <li>helhellolo</li>
              <li>hello</li>
            </ul>
          </div>
        </div>
      </div>
    </div>