How do I implement Bootstrap 4 collapse on a hierarchy of elements (navbars in my case)
I have the following hierarchy on some elements for my page and I wish to use the collapse behavior in this “tree”.
Specifically I wish the following behavior
(which I believe is the one that makes sense)
Where green means the navbar is shown, and Red means it is collapsed
With the current state
and clicking on Option B1
this simply collapses the navbar B1
In another example when clicking on option A
This shows navbar A
and collapses all descendants of option B
(navbar B and navbar B1)
The rules can be brought down to 3 simple rules:
1) When clicking on an element with some children (and possibly other descendents) active (and here active I mean shown) all the children and descendants collapse.
2) When clicking on an element X that has no active children then show the (direct) children of X AND collapse all the descendants of the siblings of X.
3) all descendants of the primary nav are loaded collapsed
I could get the desired behaviour with custom javascript code and unfortunately I needed to ignore some desired functionalities already provided by the collapse plugin from bootstrap and reimplementing them according to my need.
Go here for the Bootply
Here is the simplified HTML part
<nav id="main-nav" class="navbar navbar-expand-lg navbar-dark">
<ul class="navbar-nav align-nav">
<li class="nav-item">
<a id="togglenavA" class="nav-link" href="#" data-target="#navA" aria-controls="navA" aria-expanded="false" aria-label="Toggle navigation">Option A</a>
</li>
<li class="nav-item">
<a id="togglenavB" class="nav-link" href="#" data-target="#navB" aria-controls="navB" aria-expanded="false" aria-label="Toggle navigation">Option B</a>
</li>
</ul>
</nav>
<div id="navA" class="collapse">
<nav id="NAVA" class="navbar navbar-expand-lg navbar-dark">
<ul class="navbar-nav align-nav">
<li class="nav-item">
<a class="nav-link" href="#">Option A1</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Option A2</a>
</li>
</ul>
</nav>
</div>
<div id="navB" class="collapse">
<nav id="NAVB" class="navbar navbar-expand-lg navbar-dark">
<ul class="navbar-nav align-nav">
<li class="nav-item">
<a id="togglenavB1" class="nav-link" href="#" data-target="#navB1" aria-controls="navB1" aria-expanded="false" aria-label="Toggle navigation">Option B1</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Option B2</a>
</li>
</ul>
</nav>
</div>
<div id="navB1" class="collapse">
<nav id="NAVB1" class="navbar navbar-expand-lg navbar-dark">
<ul class="navbar-nav align-nav">
<li class="nav-item">
<a class="nav-link" href="#">Option B1.1</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Option B1.2</a>
</li>
</ul>
</nav>
</div>
And here is the Javascript that reimplements the accordion style but with the additional collapse of the sibling's children
$(document).ready(function() {
$('#togglenavA').click(function() {
$('#navB').collapse('hide')
$('#navB1').collapse('hide')
$('#navA').collapse('toggle')
$('#navA').on('hidden.bs.collapse', function () {
$('#togglenavA').attr("aria-expanded","false");
}) // for screen readers purpose
$('#navA').on('shown.bs.collapse', function () {
$('#togglenavA').attr("aria-expanded","true");
})
});
$('#togglenavB').click(function() {
$('#navA').collapse('hide')
$('#navB1').collapse('hide')
$('#navB').collapse('toggle')
$('#navB').on('hidden.bs.collapse', function () {
$('#togglenavB').attr("aria-expanded","false");
})
$('#navB').on('shown.bs.collapse', function () {
$('#togglenavB').attr("aria-expanded","true");
})
});
$('#togglenavB1').click(function() {
$('#navB1').collapse('toggle')
$('#navB1').on('hidden.bs.collapse', function () {
$('#togglenavB1').attr("aria-expanded","false");
})
$('#navB1').on('shown.bs.collapse', function () {
$('#togglenavB1').attr("aria-expanded","true");
})
});
});
Note: even though this solution solves my problem, it does so at the cost of ignoring Bootstrap's already implementation of an accordion and removing some data-attributes from some links to avoid conflicts between some automatic functionalities from the plugin with my custom code.
How it works. The collapse JavaScript plugin is used to show and hide content. Buttons or anchors are used as triggers that are mapped to specific elements you toggle. Collapsing an element will animate the height from it's current value to 0 .
Just add data-toggle="collapse" and a data-target to the element to automatically assign control of one or more collapsible elements. The data-target attribute accepts a CSS selector to apply the collapse to. Be sure to add the class collapse to the collapsible element.
In bootstrap context wise, accordion is basically a collapse button with a lot of smaller info in it. Bootstrap use card to make an accordion. on line 1, <div id="accordion" role="tablist"> , this is where the data-parent refers to. on line 2 <div class="card"> , we are using a card class, to show the card effect.
Example Explained. The . collapse class indicates a collapsible element (a <div> in our example); this is the content that will be shown or hidden with a click of a button. To control (show/hide) the collapsible content, add the data-toggle="collapse" attribute to an <a> or a <button> element.
Working Bootply example
My approach involves the following updates:
<a>
)Add the data-toggle="collapse"
attribute to the menu links. This will give you the out-of-the-box expected Bootstrap behavior for collapse. Example:
<a id="togglenavA" class="nav-link" href="#" data-toggle="collapse" data-target="#navA" aria-controls="navA" aria-expanded="false" aria-label="Toggle navigation">Option A</a>
collapse-child
This allows us to target these child navbars. Example:
<div id="navA" class="collapse collapse-child">
The JavaScript can then be simplified to just the following snippet:
$(document).ready(function() {
var hideChildren = function() {
$('div.collapse-child').collapse('hide');
};
$('a.nav-link:not([aria-controls])').click(function(el){
hideChildren();
});
$('#main-nav a').click(function(){
hideChildren();
});
});
I'm not sure if this fulfills your "without custom Javascript" requirement but I would consider it to be the "best-practice" way of achieving this with the most current version of Bootstrap4.
Ok I found a way to do this with custom javascript code and ignoring some desired functionalities provided by the collapse plugin from bootstrap and reimplementing them according to my need.
Here is the simplified HTML part
<nav id="main-nav" class="navbar navbar-expand-lg navbar-dark">
<ul class="navbar-nav align-nav">
<li class="nav-item">
<a id="togglenavA" class="nav-link" href="#" data-target="#navA" aria-controls="navA" aria-expanded="false" aria-label="Toggle navigation">Option A</a>
</li>
<li class="nav-item">
<a id="togglenavB" class="nav-link" href="#" data-target="#navB" aria-controls="navB" aria-expanded="false" aria-label="Toggle navigation">Option B</a>
</li>
</ul>
</nav>
<div id="navA" class="collapse">
<nav id="NAVA" class="navbar navbar-expand-lg navbar-dark">
<ul class="navbar-nav align-nav">
<li class="nav-item">
<a class="nav-link" href="#">Option A1</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Option A2</a>
</li>
</ul>
</nav>
</div>
<div id="navB" class="collapse">
<nav id="NAVB" class="navbar navbar-expand-lg navbar-dark">
<ul class="navbar-nav align-nav">
<li class="nav-item">
<a id="togglenavB1" class="nav-link" href="#" data-target="#navB1" aria-controls="navB1" aria-expanded="false" aria-label="Toggle navigation">Option B1</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Option B2</a>
</li>
</ul>
</nav>
</div>
<div id="navB1" class="collapse">
<nav id="NAVB1" class="navbar navbar-expand-lg navbar-dark">
<ul class="navbar-nav align-nav">
<li class="nav-item">
<a class="nav-link" href="#">Option B1.1</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Option B1.2</a>
</li>
</ul>
</nav>
</div>
And here is the Javascript that reimplements the accordion style but with the additional collapse of the sibling's children
$(document).ready(function() {
$('#togglenavA').click(function() {
$('#navB').collapse('hide')
$('#navB1').collapse('hide')
$('#navA').collapse('toggle')
$('#navA').on('hidden.bs.collapse', function () {
$('#togglenavA').attr("aria-expanded","false");
}) // for screen readers purpose
$('#navA').on('shown.bs.collapse', function () {
$('#togglenavA').attr("aria-expanded","true");
})
});
$('#togglenavB').click(function() {
$('#navA').collapse('hide')
$('#navB1').collapse('hide')
$('#navB').collapse('toggle')
$('#navB').on('hidden.bs.collapse', function () {
$('#togglenavB').attr("aria-expanded","false");
})
$('#navB').on('shown.bs.collapse', function () {
$('#togglenavB').attr("aria-expanded","true");
})
});
$('#togglenavB1').click(function() {
$('#navB1').collapse('toggle')
$('#navB1').on('hidden.bs.collapse', function () {
$('#togglenavB1').attr("aria-expanded","false");
})
$('#navB1').on('shown.bs.collapse', function () {
$('#togglenavB1').attr("aria-expanded","true");
})
});
});
Note: even though this solution solves my problem, it does so at the cost of ignoring Bootstrap's already implementation of an accordion and removing some data-attributes from some links to avoid conflicts between some automatic functionalities from the pliguin with my custom code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With