JSFiddle - React, Tailwind, and code Playground
HTML
<button id="elToggle">toggle</button>
<hr />
<div class="block" style="width: 200px; border: 2px solid;" id="elBlock">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Repellat, voluptatibus, corporis! Impedit nostrum, quibusdam officia alias suscipit totam molestiae magni, vel quos. Tempora perspiciatis animi in qui quod officiis quia.</div>
CSS
.block {
overflow: hidden;
transition: height 500ms ease;
}
.is-collapsed {
height: 0;
}
JavaScript
let isAnimating = false;
function isCollapsed(element) {
return element.classList.contains('is-collapsed');
}
function onSchedule(fn) {
/* да, здесь два requestAnimationFrame */
requestAnimationFrame(function() {
requestAnimationFrame(function() {
fn();
});
});
}
function open(element) {
isAnimating = true;
element.style.height = `${element.scrollHeight}px`;
onSchedule(function() {
element.classList.remove('is-collapsed');
element.addEventListener("transitionend", function onTransitionEnd() {
element.removeEventListener("transitionend", onTransitionEnd);
element.style.height = "";
isAnimating = false;
});
})
}
function close(element) {
isAnimating = true;
element.style.height = `${element.scrollHeight}px`;
onSchedule(function() {
element.classList.add('is-collapsed');
element.style.height = "";
element.addEventListener("transitionend", function onTransitionEnd() {
element.removeEventListener("transitionend", onTransitionEnd);
isAnimating = false;
});
});
}
elToggle.addEventListener("click", () => {
if (isAnimating) return;
isCollapsed(elBlock) ? open(elBlock) : close(elBlock);
});