49

I am trying to mimic the Outlook bar using Twitter bootstrap using the accordion and collapse plugin, so far I got the collapse and accordion working, but it presently allows for all sections to be collapsed.

I would like to limit it so that one and only one is always shown.

Here is the one I am working on: http://jsfiddle.net/trajano/SMT9D/ and I think it's somewhere along the lines of

$('#accordions').on('hide', function (event) { console.warn("HIDE TRIGGERED, check if trying to hide the active one if so stop"); }) 

13 Answers 13

78

Here is an easy way to do it:

Bootstrap 4

$('.accordion .btn-link').on('click', function(e) { if (!$(this).hasClass('collapsed')) { e.stopPropagation(); } }); 

from @mr_joncollette in the comments

Bootstrap 3

JsFiddle for Bootstrap 3.

Code for Bootstrap 3:

$('.panel-heading a').on('click',function(e){ if($(this).parents('.panel').children('.panel-collapse').hasClass('in')){ e.stopPropagation(); } // You can also add preventDefault to remove the anchor behavior that makes // the page jump // e.preventDefault(); }); 

The code checks if the clicked element is the one that is currently shown (by the class "in") and if it does have the "in" class, it stops the hiding process.


Deprecated Bootstrap 2

JsFiddle for Bootstrap 2.

Code for Bootstrap 2:

$('.accordion-toggle').on('click',function(e){ if($(this).parents('.accordion-group').children('.accordion-body').hasClass('in')){ e.stopPropagation(); } // You can also add preventDefault to remove the anchor behavior that makes // the page jump // e.preventDefault(); }); 

Note: Be careful if you want to attach more click events on the accordion, since the e.stopPropagation() will block events that would occur after the check.

Sign up to request clarification or add additional context in comments.

3 Comments

thank you for this! didn't use the exact same solution, but e.stopPropagation() was what i needed!
Nice add e.preventDefault(); after if statement and your page won't jump on click
Beautiful — works with Bootstrap 4.5 $('.accordion .btn-link').on('click', function(e) { if (!$(this).hasClass('collapsed')) { e.stopPropagation(); } });
13

Updated 2018

Here's how to keep at least open in both Bootstrap v3 or v4. This means that the open accordion can only be closed by toggling another one open.

Bootstrap 4

https://www.codeply.com/go/bbCcnl0jBB

// the current open accordion will not be able to close itself $('[data-toggle="collapse"]').on('click',function(e){ if ( $(this).parents('.accordion').find('.collapse.show') ){ var idx = $(this).index('[data-toggle="collapse"]'); if (idx == $('.collapse.show').index('.collapse')) { e.stopPropagation(); } } }); 

Also, see this answer which shows how to specify a "default" accordion that will open when all others are closed.


Bootstrap 3

$('[data-toggle="collapse"]').on('click',function(e){ if($(this).parents('.panel').find('.collapse').hasClass('in')){ var idx = $(this).index('[data-toggle="collapse"]'); var idxShown = $('.collapse.in').index('.accordion-body'); if (idx==idxShown) { e.stopPropagation(); } } }); 

https://www.codeply.com/go/yLw944BrgA

<div class="accordion" id="myAccordion"> <div class="panel"> <button type="button" class="btn btn-danger" data-toggle="collapse" data-target="#collapsible-1" data-parent="#myAccordion">Question 1?</button> <div id="collapsible-1" class="collapse"> .. </div> </div> <div class="panel"> <button type="button" class="btn btn-danger" data-toggle="collapse" data-target="#collapsible-2" data-parent="#myAccordion">Question 2?</button> <div id="collapsible-2" class="collapse"> .. </div> </div> <div class="panel"> <button type="button" class="btn btn-danger" data-toggle="collapse" data-target="#collapsible-3" data-parent="#myAccordion">Question 3?</button> <div id="collapsible-3" class="collapse"> ... </div> </div> </div> 

(Note: the panel class is needed in Bootstrap 3 to make the accordion behavior work)

2 Comments

can you please help me to solve this stackoverflow.com/questions/50206963/…
The example for B4 is not working for some reason, even on codeply.
10

I want to precise @Hugo Dozois 's answer

http://jsfiddle.net/SMT9D/61/

You should add e.preventDefault(); to prevent the default behaviour of # HTML anchor if you have a scroll in your page

$('.panel-heading a').on('click',function(e){ if($(this).parents('.panel').children('.panel-collapse').hasClass('in')){ e.preventDefault(); e.stopPropagation(); } }); 

Comments

9

Or you can use simple CSS trick as follows:

/* prevent the active panel from collapsing */ .panel-group [aria-expanded=true]{ /* http://caniuse.com/#feat=pointer-events Works for MOST modern browsers. (- Opera Mobile) */ pointer-events: none; } 

must have proper tags on the inactive panel links

 aria-expanded="false" 

1 Comment

It works, but for already not-collapsed elements, it won't. Only in the second action.
8

As all the other JS answers use an inadvisable stopPropagation() here is my solution using just the native Bootstrap events (tested on Bootstrap 4).

JsFiddle

$('#accordionExample').on('show.bs.collapse', function () { $(this).data('isShowing', true); }); $('#accordionExample').on('hide.bs.collapse', function (event) { if (!$(this).data('isShowing')) { event.preventDefault(); } $(this).data('isShowing', false); }); 

It makes use of the fact that a click on a collapsed element will result in a show.bs.collapse followed by a hide.bs.collapse. Whereas a click on the open element will result in just a hide.bs.collapse.

Comments

2

None of the provided solutions allow to have more than one accordion in the same page, keeping or not one tab opened.

Here's mine solution:

$("[data-toggle=buttons][data-oneopen=true] [data-toggle=collapse]").on("click", function (e) { var me = $(this); var target = $(me.attr("data-target") || me.attr("href")); if (target.hasClass("show")) { e.stopPropagation(); } }); 

First I've chosen a data-oneopen attribute to flag those accordion buttons to enable this behaviour, but it can be replaced for a class or any other selector.

Then I check data-target and href attributes to find related tab.

Finally I stopPropagation if the item has show class, just change it for a in class to have a solution for Bootstrap 3.

Comments

2

Bootstrap 5

Omit the data-bs-parent attribute on each .accordion-collapse to make accordion items stay open when another item is opened.

1 Comment

This solution does not apply to the question "Keep one group open" because it still allows collapsing the only one opened keeping none opened
2

Solution for Bootstrap-5

$(this).on('mouseenter', function (e) { if( !$(this).hasClass('collapsed')) { $(this).attr('data-bs-toggle','disabled'); } }) $(this).on('mouseleave', function (e) { if( !$(this).hasClass('collapsed')) { $(this).attr('data-bs-toggle','collapse'); } }) 

Hope it helps Andreas

1 Comment

you can also use the show.bs.collapse and hide.bs.collapse events to enable/disable the buttons. especially on touch screens
1

Bootstrap 4.0

$('.card').click(function(e) { if ( $(this) .find('.collapse') .hasClass('show') ) { e.stopPropagation(); } }); 

This code block checks if the clicked card is collapsed (by looking at the div with the class collapse). When the card is currently shown it stops propagating the event.

1 Comment

I suggest - besides better styling - to use the .on("click", function...) way in order to ensure it works after the first time as well.
1

I have a scenario that do not fit with any posted answer: multiple accordions on the same page and some other collapsible components that are not accordions (without data-parent attribute).

$("[data-toggle=collapse][data-parent]").click(function (e) { var button = $(this); var parent = $(button.attr("data-parent")); var panel = parent.find(button.attr("href") || button.attr("data-target")); if (panel.hasClass("in")) { e.preventDefault(); e.stopPropagation() } }); 

This code only triggers on accordions, since checks data-parent attribute. It also does not assume a card (or panel for bootstrap 3) structure, it uses the same attributes that bootstrap api.

I hope it helps.

Comments

1

Bootstrap 5

Alternate solution from @awant. This time using the collapse events to disable the button. This works great with touch screens.

$(this).on('show.bs.collapse', function (e) { $(buttonSelector).attr('data-bs-toggle','disabled'); }) $(this).on('hide.bs.collapse', function (e) { $(buttonSelector).attr('data-bs-toggle','collapse'); }) 

Comments

1

Bootstrap 5

.accordion-button:not(.collapsed) { pointer-events: none; } 

2 Comments

Thanks that looks like a simple solution. Please explain how it works though.
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
-1

As per bootstarp 3.3.6 version , just follow structure

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous"> <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true"> <div class="panel panel-default"> <div class="panel-heading" role="tab" id="headingOne"> <h4 class="panel-title"> <a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne"> Collapsible Group Item #1 </a> </h4> </div> <div id="collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne"> <div class="panel-body"> collopse 1 body here </div> </div> </div> <div class="panel panel-default"> <div class="panel-heading" role="tab" id="headingTwo"> <h4 class="panel-title"> <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"> Collapsible Group Item #2 </a> </h4> </div> <div id="collapseTwo" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingTwo"> <div class="panel-body"> collapse body 2 </div> </div> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>

3 Comments

@Artistan This solution works properly. But it works in conjunction the panel component. Collapsible blocks must to be children of the block, which has the panel class. You can use this answer as an example.
@gleb-kemarsky it doesn't. the subject says clearly "keep one group open" and your "solution" allows collapsing the only one opened "keeping none opened".
@kpull1 Thanks for the clarification. It seems that I misunderstood with what difficulties the author of the question encountered.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.