JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://code.jquery.com/jquery-3.4.1.slim.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.css">
<button class="btn btn-dark np-trigger" data-target="#menu">Menu</button>
<nav id="menu" class="bg-dark navigation-menu np-collapsible">
<a class="nav-link" href="#">Link</a>
<a class="nav-link" href="#">Link</a>
<a class="nav-link" href="#">Link</a>
</nav>
CSS
.np-collapsible:not(.np-expanded) {
display: none;
}
.np-transitioning {
height: 0;
overflow: hidden;
transition: height 0.25s ease;
}
.navigation-menu {
display: flex;
flex-direction: column;
position: fixed;
top: 4rem;
left: 1rem;
width: 270px;
}
JavaScript
var button = document.querySelector('.np-trigger');
var menu = document.querySelector(button.dataset.target);
button.addEventListener('click', function(event) {
if (menu.classList.contains('np-expanded')) {
alert('Menu is already expanded.');
} else {
expand();
}
}, false);
function expand() {
if (isTransitioning()) {
// Don't do anything during a transition
return;
}
// Restore menu visibility
menu.classList.remove('np-collapsible');
// Retrieve the height of the menu
var targetHeight = menu.offsetHeight + 'px';
// Enable transition and set height to 0
menu.classList.add('np-transitioning');
menu.addEventListener('transitionend', function(event) {
// Disable transition
menu.classList.remove('np-transitioning');
// Indicate that the menu is now expanded
menu.classList.add('np-collapsible');
menu.classList.add('np-expanded');
button.setAttribute('aria-expanded', true);
}, {once: true});
// Set the height to execute the transition
menu.style.height = targetHeight;
}
function isTransitioning() {
if (menu.classList.contains('np-transitioning')) {
return true;
}
return false;
}