Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Hiding element visible with :focus-within when sibling has :hover state

I’m working on a navigation component and want the nav element to be visible, using display: block when it has :focus-within for keyboard navigation. This state seems to be applying when I click the nav button, but remains visible when I hover sibling elements. I would like the focus-within state to be hidden when a sibling has the hover state.

Given the following HTML

    <ul>
      <li>
        <button>
        One
        </button>
        <span>
          submenu 1
        </span>
      </li>
      <li>
        <button>
          Two
        </button>
        <span>
          submenu 2
        </span>
      </li>
      <li>
        <button>
          Three
        </button>
        <span>
          submenu 3
        </span>
          
      </li>
    </ul>

and the following CSS

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

span {
  display: none;
}

li {
  &:hover > span {
    display: block;
  }
  
  &:focus-within > span {
    display: block;
  }
}

Codepen implementation

I can show the submenu items when I click or keyboard navigate the page. However, if I click <button>One and then hover <button>Two, submenu 1 remains visible. The submenu should only be visible if it has 1) :hover state or 2) :focus-within state (but no sibling has hover state).

I would like no more than 1 submenu visible at once. Is this possible to achieve with CSS?

>Solution :

Yes, it is:

li:hover ~ li:focus-within,
li:focus-within:has(~ li:hover) {
  display: none;
}

Note that :has() is not very well supported (yet).

Try it:

span {
  display: none;
}

li:hover > span {
  display: block;
}

li:focus-within > span {
  display: block;
}

li:hover ~ li:focus-within,
li:focus-within:has(~ li:hover) {
  display: none;
}
<ul>
  <li>
    <button>One</button>
    <span>submenu 1</span>
  </li>
  <li>
    <button>Two</button>
    <span>submenu 2</span>
  </li>
  <li>
    <button>Three</button>
    <span>submenu 3</span>
  </li>
</ul>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading