Please help, I want the toggle buttons to only show and hide the paragraphs but the other contents inside the div
should remain always visible. Also, the CSS is the same and I am trying to smoothen the transition of the DIV's height when showing and hiding the paragraphs
const toggleButtons = document.querySelectorAll('.toggleButton');
const divs = document.querySelectorAll('div');
const paragraphs = document.querySelectorAll('.paragraph');
toggleButtons.forEach((button, index) => {
button.addEventListener('click', () => {
const paragraph = paragraphs[index];
paragraph.classList.toggle('hidden');
paragraph.classList.toggle('visible');
if (paragraph.classList.contains('visible')) {
divs[index].style.height = paragraph.scrollHeight + 'px';
} else {
divs[index].style.height = '0';
}
});
});
div {
height: 0;
overflow: hidden;
transition: height 0.5s;
background: blue;
}
.paragraph {
opacity: 0;
transition: opacity 0.5s;
}
.visible {
opacity: 1;
display: block;
}
.hidden {
opacity: 0;
display: none;
}
<button class="toggleButton">Toggle 1</button>
<div> HI
<p class="paragraph hidden">Paragraph 1.</p>
</div>
<button class="toggleButton">Toggle 2</button>
<div> Hi
<p class="paragraph hidden">Paragraph 2.</p>
</div>
<button class="toggleButton">Toggle 3</button>
<div> Hi
<p class="paragraph hidden">Paragraph 3.</p>
</div>
While waiting for all browsers to support
height: calc-size(auto);
/* Currently in Canary - Experimental features */
Here are several ways to toggle-animate an element's height
Currently supported in Chromium
.content {
interpolate-size: allow-keywords;
transition: height 0.6s;
overflow: hidden;
height: 0;
}
button:focus + * > .content {
height: auto;
}
<button type="button">Toggle 1</button>
<div>
<div>Short intro 1</div>
<div class="content" id="content_1">
1. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias labore fuga quia, iste rerum nulla, reprehenderit at quasi id omnis dolorem. Iusto repellendus nemo reiciendis rerum facere maxime dicta. Fugit.
</div>
</div>
<button type="button">Toggle 2</button>
<div>
<div>Short intro 2</div>
<div class="content" id="content_2">
2. Lorem ipsum dolor sit ametIusto repellendus nemo reiciendis rerum facere maxime dicta. Fugit.
</div>
</div>
<button type="button">Toggle 3</button>
<div>
<div>Short intro 3</div>
<div class="content" id="content_3">
3. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatibus id similique laboriosam eos perspiciatis aliquam corporis esse veniam ab aspernatur debitis, provident rerum nemo blanditiis! Beatae delectus, provident totam iusto.
</div>
</div>
The display
property cannot be transitioned (animated). Also, the trick to transition max-height
is fundamentally broken since it does not work well when collapsing during a defined amount of time; makes use of magic numbers to transition to: max-height: "big-magic-number"unit;
) causing animation gaps or unwanted scrollbars when using values like 100%|vh
.
Solution:
transition (animate) the carousel element using CSS grid
and
grid-template-rows
from 0fr
to 1fr
document.querySelectorAll('[data-toggle]').forEach(elBtn => {
elBtn.addEventListener("click", () => {
document.querySelector(elBtn.dataset.toggle).classList.toggle("open");
});
});
.content {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.5s ease-in-out;
&.open {
grid-template-rows: 1fr;
}
.content-inner {
overflow: hidden;
}
}
<button type="button" data-toggle="#content_1">Toggle 1</button>
<div> HI
<div class="content" id="content_1">
<div class="content-inner">
1. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias labore fuga quia, iste rerum nulla, reprehenderit at quasi id omnis dolorem. Iusto repellendus nemo reiciendis rerum facere maxime dicta. Fugit.
</div>
</div>
</div>
<button type="button" data-toggle="#content_2">Toggle 2</button>
<div> HI
<div class="content" id="content_2">
<div class="content-inner">
2. Lorem ipsum dolor sit ametIusto repellendus nemo reiciendis rerum facere maxime dicta. Fugit.
</div>
</div>
</div>
<button type="button" data-toggle="#content_3">Toggle 3</button>
<div> HI
<div class="content" id="content_3">
<div class="content-inner">
3. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatibus id similique laboriosam eos perspiciatis aliquam corporis esse veniam ab aspernatur debitis, provident rerum nemo blanditiis! Beatae delectus, provident totam iusto.
</div>
</div>
</div>
<hr>
<button type="button" data-toggle="#content_3">I also toggle 3.</button>
Also, don't use <p>
as your carousel collapsible element. Animate display-block elements like DIV. <p>
might be indeed a display-block element, but historically served the purpose as a styled content wrapper, and should be used for content and semantics, not as an architectural block, that animates.
Accessibility
For simplification-of-answer I missed to, but don't forget to add the needed A11Y Aria attributes and the needed JS code to toggle the aria-expanded="true"
"false"
values on click - an example on how to achieve that can be found on this related Answer: Toggle Animate Details Height from 0 to auto
Acknowledgments: