Dropdown does not disappear when focus

Viewed 161

I wanted to make a drop down menu that would display sub-menus on a click using CSS pseudo class called focus-within, but it does not work if I click the dropdown menu (Click to dropdown) again.

I have added the code in the code snippet, so you can run the example.

.example-menu {
    list-style: none;
    padding: 0;
    margin: 0;
    display: inline-flex;
    flex-direction: row;
    background: #ffffff;
    border: solid 2px #000000;

}

.example-dropdown {
    position: relative;
}

.example-dropdown > ul {
    list-style: none;
    padding: 0;
    margin: 0;
    display: none;
    flex-direction: column;
    position: absolute;
    background: #ffffff;
    border: solid 2px #000000;
}

.example-dropdown:focus-within > ul {
    display: flex;
}

.example-menu a {
    display: inline-block;
    padding: 0.5rem;
}

.example-dropdown > a {
    display: inline-block;
    padding: 1rem;
    color: #000000;
}

.example-dropdown > a::after {
    content: " \2193"
}
 <ul class="example-menu">
    <li class="example-dropdown">
        <a tabindex="0">Click to dropdown</a>
        <ul>
            <li><a href="http://example.com">Link</a></li>
            <li><a href="http://example.com">Link</a></li>
            <li class="example-dropdown">
                <a tabindex="0">Click to dropdown</a>
                <ul>
                    <li><a href="http://example.com">Link</a></li>
                    <li><a href="http://example.com">Link</a></li>
                    <li><a href="http://example.com">Link</a></li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

The dropdown does not disappear.

Is there any way to make it work?

2 Answers

You need to implement JavaScript to achieve the toggle feature.

This is the code for the JS part that'll achieve what you're looking for:

// Parent Dropdown Menu
let menu1 = document.getElementById('parentMenu');
let list1 = document.getElementById('parentList');

// Child Dropdown Menu
let menu2 = document.getElementById('childMenu');
let list2 = document.getElementById('childList');

// Toggle Effect
menu1.onclick = function() {
    if (list1.style.display === 'block') {
        list1.style.display = 'none';
    }
    else {
        list1.style.display = 'block';
    }
}

menu2.onclick = function() {
    if (list2.style.display === 'block') {
        list2.style.display = 'none';
    }
    else {
        list2.style.display = 'block';
    }
}

The only change you need to do to your code is to add IDs for the parts you want to take this effect.

I added the effect to both of your dropdowns(Parent and Child).

Parent:

...
<a tabindex="0" id="parentMenu">Click to dropdown</a>
<ul id="parentList">
...

Child:

...
<a tabindex="0" id="childMenu">Click to dropdown</a>
<ul id="childList">
...

// Parent Dropdown Menu
let menu1 = document.getElementById('parentMenu');
let list1 = document.getElementById('parentList');

// Child Dropdown Menu
let menu2 = document.getElementById('childMenu');
let list2 = document.getElementById('childList');

// Toggle Effect
menu1.onclick = function() {
    if (list1.style.display === 'block') {
        list1.style.display = 'none';
    }
    else {
        list1.style.display = 'block';
    }
}

menu2.onclick = function() {
    if (list2.style.display === 'block') {
        list2.style.display = 'none';
    }
    else {
        list2.style.display = 'block';
    }
}
.example-menu {
    list-style: none;
    padding: 0;
    margin: 0;
    display: inline-flex;
    flex-direction: row;
    background: #ffffff;
    border: solid 2px #000000;

}

.example-dropdown {
    position: relative;
}

.example-dropdown > ul {
    list-style: none;
    padding: 0;
    margin: 0;
    display: none;
    flex-direction: column;
    position: absolute;
    background: #ffffff;
    border: solid 2px #000000;
}

.example-dropdown:focus-within > ul {
    display: flex;
}

.example-menu a {
    display: inline-block;
    padding: 0.5rem;
}

.example-dropdown > a {
    display: inline-block;
    padding: 1rem;
    color: #000000;
}

.example-dropdown > a::after {
    content: " \2193"
}
 <ul class="example-menu">
    <li class="example-dropdown">
        <a tabindex="0" id="parentMenu">Click to dropdown</a>
        <ul id="parentList">
            <li><a href="http://example.com">Link</a></li>
            <li><a href="http://example.com">Link</a></li>
            <li class="example-dropdown">
                <a tabindex="0" id="childMenu">Click to dropdown</a>
                <ul id="childList">
                    <li><a href="http://example.com">Link</a></li>
                    <li><a href="http://example.com">Link</a></li>
                    <li><a href="http://example.com">Link</a></li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

I hope this was what you were looking for as your question was a bit unclear regarding where exactly you wanted the toggle effect.

If you don't want to use JavaScript you can try something like down below.

First you should add a checkbox element to your html.

<ul class="example-menu">
    <li class="example-dropdown">
        <a tabindex="0">Click to dropdown</a>
        <input type="checkbox" class="click_effect" name="" id="index-0">
        <ul>
            <li><a href="http://example.com">Link</a></li>
            <li><a href="http://example.com">Link</a></li>
            <li class="example-dropdown">
                <a tabindex="0">Click to dropdown</a>
                <input type="checkbox" class="click_effect" name="" id="index-1">
                <ul>
                    <li><a href="http://example.com">Link</a></li>
                    <li><a href="http://example.com">Link</a></li>
                    <li><a href="http://example.com">Link</a></li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

Then you sould add some new properties in css file.

#index-0:checked + ul, #index-1:checked + ul {
  display: flex;
}

Now you will need to remove the code below.

.example-dropdown:focus-within > ul {
    display: flex;
}
Related