I have a set of collapsible elements whose visibility is controlled via data-bs-toggle="collapse"
/data-bs-target
, and only one should be visible at a given time.
This behavior is achieved with data-bs-parent
.
The issue is that the currently visible element can still be collapsed, hence no elements are visible afterward.
How to prevent collapsing of the currently visible element?
Elements should be collapsed only when another one is made visible.
e.g. in the sample: at the beginning #1
is visible, if I click on the controlling span it is hidden, hence no content is visible anymore, it should stay visible as long as no other content is visible.
span[data-bs-toggle] { cursor : pointer; }
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<span data-bs-toggle="collapse" data-bs-target="#content1">#1</span>
<span data-bs-toggle="collapse" data-bs-target="#content2">#2</span>
<span data-bs-toggle="collapse" data-bs-target="#content3">#3</span>
<div id="container">
<span id="content1" class="collapse show" data-bs-parent="#container">#1+</span>
<span id="content2" class="collapse" data-bs-parent="#container">#2+</span>
<span id="content3" class="collapse" data-bs-parent="#container">#3+</span>
</div>
You'll need to do it with JavaScript, which will toggle elements according to your logic, which means you'll also need to initialize BS collapsibles with JavaScript.
So, you need to prevent toggling, if its target is already shown. You could add click listeners to each toggler, find corresponding target, check if it's already showing, and then toggle if not:
// initialize collapsibles, do not toggle initially
const collapseElementList = document.querySelectorAll('.collapse');
const collapseList = [...collapseElementList].map(collapseEl => (new bootstrap.Collapse(collapseEl, {
toggle: false,
parent: '#container'
})));
// add click listeners to each toggler
// toggle only if its target isn't already shown
const btns = document.querySelectorAll('span').forEach((btn, i) => {
btn.addEventListener('click', e => {
if (!collapseList[i]._element.classList.contains('show')) collapseList[i].toggle();
});
});
demo:
// initialize collapsibles, do not toggle initially
const collapseElementList = document.querySelectorAll('.collapse');
const collapseList = [...collapseElementList].map(collapseEl => (new bootstrap.Collapse(collapseEl, {
toggle: false,
parent: '#container'
})));
// add click listeners to each toggler
// toggle only if its target isn't already shown
const btns = document.querySelectorAll('span').forEach((btn, i) => {
btn.addEventListener('click', e => {
if (!collapseList[i]._element.classList.contains('show')) collapseList[i].toggle();
});
});
span[data-bs-toggle] {
cursor: pointer;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<span data-bs-target="#content1">#1</span>
<span data-bs-target="#content2">#2</span>
<span data-bs-target="#content3">#3</span>
<div id="container">
<span id="content1" class="collapse show">#1+</span>
<span id="content2" class="collapse">#2+</span>
<span id="content3" class="collapse">#3+</span>
</div>