Search code examples
htmlcssfocustoggle

Have :focus Toggle Items Including If You Click The Parent Item Again


I have a simple submenu that is toggled into visibility using the :focus CSS selector.

It shows the submenu by turning the submenu from display: none to display: block with the following CSS:

.menu-item:focus > .submenu {
  display: block;
}

This all works, and if I click on a different menu item (or anywhere else on the page) the submenu then disappears.

Is it possible however with CSS (and I'm guessing :focus) to have it so when I click on the initial menu-item again (i.e. for a 2nd time) it also toggles away? At the moment this isn't happening - it is only happening when I click anywhere else (which is clearly when the element loses focus).

Many thanks

Codepen: https://codepen.io/emilychews/pen/RwVVmjm

body {
  display: flex;
  justify-content: center;
  margin: 0;
  height: 100vh;
  width: 100%;
}

header {
  margin-top: 2rem;
  display: flex;
  width: 50%;
  justify-content: space-evenly;
  align-items: center;
  padding: 1rem;
  background: red;
  height: 2rem;
}

.menu-item {
  position: relative;
  padding: 1rem;
  background: yellow;
  cursor: pointer;
}

/* select the focused menu-item's child elements (the submenu) */
.menu-item:focus > .submenu {
  display: block;
}

.submenu {
  display: none; /* changes to 'block' with focus */
  padding: 1rem;
  background: lightblue;
  position: absolute;
  top: 4rem;
  left: 0;
  width: 6rem;
}
<header>
  <div id="item-1" class="menu-item menu-item-1" tabindex="0">ITEM 1
    <div id="sub-item-1" class="submenu submenu-1">SUB-ITEM-1</div>
  </div>
  <div id="item-2" class="menu-item menu-item-2" tabindex="0">ITEM 2
    <div id="sub-item-2" class="submenu submenu-2">SUB-ITEM-2</div>
  </div>
</header>


Solution

  • The best way for my opinion is to use JavaScript.
    However you can use checkbox and changing the wrapper div to label for only CSS solution :

    body {
      display: flex;
      justify-content: center;
      margin: 0;
      height: 100vh;
      width: 100%;
    }
    
    header {
      margin-top: 2rem;
      display: flex;
      width: 50%;
      justify-content: space-evenly;
      align-items: center;
      padding: 1rem;
      background: red;
      height: 2rem;
    }
    
    .menu-item {
      position: relative;
      padding: 1rem;
      background: yellow;
      cursor: pointer;
      
    }
    
    /* select the element after the checked checkbox  (the submenu) */
    .dis:checked ~ .submenu {
      display: block;
    }
    
    .dis{ /*reset default checkbox style*/
      display: none
    }
    .submenu {
      display: none; /* changes to 'block' with focus */
      padding: 1rem;
      background: lightblue;
      position: absolute;
      top: 4rem;
      left: 0;
      width: 6rem;
    }
    <header>
      <label id="item-1" class="menu-item menu-item-1" tabindex="0">ITEM 1
      <input type="checkbox" class="dis">
        <div id="sub-item-1" class="submenu submenu-1">SUB-ITEM-1</div>
        
      </label>
      <label id="item-2" class="menu-item menu-item-2" tabindex="0">ITEM 2
      <input type="checkbox" class="dis">
        <div id="sub-item-2" class="submenu submenu-2">SUB-ITEM-2</div>
        
      </label>
    </header>