I'm trying to implement a simple dropdown with a slideDown effect. To build this effect I used a CSS transition
applied to the height
property.
Problem is that if I press the Tab ↹
key, any targetable element (tab stops) inside the dropdown will be targeted, even when it is hidden as I am not using display: none
.
Here's the code:
const button = document.getElementById('button');
const dropdown = document.getElementById('dropdown');
dropdown.style.setProperty('height', 'auto', 'important');
dropdown.style.setProperty('height', dropdown.clientHeight + 'px');
button.addEventListener('click', function(e) {
e.target.classList.toggle('active');
e.target.nextElementSibling.classList.toggle('active');
});
#dropdown {
overflow: hidden;
transition: height 330ms linear;
background-color: lightgrey;
height: 200px;
}
#dropdown:not(.active) {
height: 0 !important;
}
#dropdown.active {
visibility: visible;
}
<button id="button">Click me!</button>
<div id="dropdown">
<a href="#">I should not be accessible with tab when dropdown is hidden</a>
</div>
<div id="info">This link will be focused after three tabs, instead of two: <a href="#">Tab me!</a></div>
I have tried to modify the code a little bit using the transitionend
event to add and remove display: none
when the transition ends thus making any targetable elements inside the dropdown untargetable, but this messes up with the starting animation of the transition.
See:
const button = document.getElementById('button');
const dropdown = document.getElementById('dropdown');
dropdown.style.setProperty('height', 'auto', 'important');
dropdown.style.setProperty('height', dropdown.clientHeight + 'px');
dropdown.classList.add('hidden');
button.addEventListener('click', function(e) {
if (!e.target.classList.contains('active'))
dropdown.classList.remove('hidden');
e.target.classList.toggle('active');
e.target.nextElementSibling.classList.toggle('active');
});
dropdown.addEventListener('transitionend', function(e) {
dropdown.classList.add('hidden');
});
#dropdown {
overflow: hidden;
transition: height 330ms linear;
background-color: lightgrey;
height: 200px;
}
#dropdown:not(.active) {
height: 0 !important;
}
#dropdown.active {
visibility: visible;
}
a {
display: block; /* so it doesn't move when dropdown is hidden */
}
.hidden {
display: none;
}
<button id="button">Click me!</button>
<div id="dropdown">
<a href="#">I should not be accessible with tab when dropdown is hidden</a>
</div>
<div id="info">This link will now be focused after <strong>two</strong> tabs, as expected: <a href="#">Tab me!</a></div>