[javascript] jQuery UI Accordion Expand/Collapse All

I'm using the jQuery UI Accordion (which does not allow more than one item open at a time) on a project. Using accordion is appropriate since I usually do only want one panel open at a time.

However, I need to offer an "Expand All" link which switches to "Collapse All" when clicked. I don't want to custom write near-identical accordion functionality around this one requirement, so I'd like some JS that will achieve this whilst keeping the Accordion component in use.

Question: What JavaScript/jQuery is required to achieve this whilst still using the jQuery UI "Accordion" component to power the standard functionality?

Here's a fiddle: http://jsfiddle.net/alecrust/a6Cu7/

The answer is


A lot of these seem to be overcomplicated. I achieved what I wanted with just the following:

$(".ui-accordion-content").show();

JSFiddle


Here's the code by Sinetheta converted to a jQuery plugin: Save below code to a js file.

$.fn.collapsible = function() {
    $(this).addClass("ui-accordion ui-widget ui-helper-reset");
    var headers = $(this).children("h3");
    headers.addClass("accordion-header ui-accordion-header ui-helper-reset ui-state-active ui-accordion-icons ui-corner-all");
    headers.append('<span class="ui-accordion-header-icon ui-icon ui-icon-triangle-1-s">');
    headers.click(function() {
        var header = $(this);
        var panel = $(this).next();
        var isOpen = panel.is(":visible");
        if(isOpen)  {
            panel.slideUp("fast", function() {
                panel.hide();
                header.removeClass("ui-state-active")
                    .addClass("ui-state-default")
                    .children("span").removeClass("ui-icon-triangle-1-s")
                        .addClass("ui-icon-triangle-1-e");
          });
        }
        else {
            panel.slideDown("fast", function() {
                panel.show();
                header.removeClass("ui-state-default")
                    .addClass("ui-state-active")
                    .children("span").removeClass("ui-icon-triangle-1-e")
                        .addClass("ui-icon-triangle-1-s");
          });
        }
    });
}; 

Refer it in your UI page and call similar to jQuery accordian call:

$("#accordion").collapsible(); 

Looks cleaner and avoids any classes to be added to the markup.


I tried the old-fashioned version, of just adjusting aria-* and CSS attributes like many of these older answers, but eventually gave up and just did a conditional fake-click. Works a beaut':

HTML:

<a href="#" onclick="expandAll();"
  title="Expand All" alt="Expand All"><img
    src="/images/expand-all-icon.png"/></a>
<a href="#" onclick="collapseAll();"
  title="Collapse All" alt="Collapse All"><img
    src="/images/collapse-all-icon.png"/></a>

Javascript:

async function expandAll() {
  let heads = $(".ui-accordion-header");
  heads.each((index, el) => {
    if ($(el).hasClass("ui-accordion-header-collapsed") === true)
      $(el).trigger("click");
  });
}

async function collapseAll() {
  let heads = $(".ui-accordion-header");
  heads.each((index, el) => {
    if ($(el).hasClass("ui-accordion-header-collapsed") === false)
      $(el).trigger("click");
  });
}


(The HTML newlines are placed in those weird places to prevent whitespace in the presentation.)


Using an example about for Taifun, I modified to allow expand and collapse.

... // hook up the expand/collapse all

var expandLink = $('.accordion-expand-all');

expandLink.click(function () {

$(".ui-accordion-content").toggle();
});

You can try this lightweight small plugin.

It will allow you customize it as per your requirement. It will have Expand/Collapse functionality.

URL: http://accordion-cd.blogspot.com/


This my solution:

Working in real project.

   $(function () {
    $("#accordion").accordion({collapsible:true, active:false});
    $('.open').click(function () {
        $('.ui-accordion-header').removeClass('ui-corner-all').addClass('ui-accordion-header-active ui-state-active ui-corner-top').attr({'aria-selected':'true','tabindex':'0'});
        $('.ui-accordion-header .ui-icon').removeClass('ui-icon-triangle-1-e').addClass('ui-icon-triangle-1-s');
        $('.ui-accordion-content').addClass('ui-accordion-content-active').attr({'aria-expanded':'true','aria-hidden':'false'}).show();
        $(this).hide();
        $('.close').show();
    });
    $('.close').click(function () {
        $('.ui-accordion-header').removeClass('ui-accordion-header-active ui-state-active ui-corner-top').addClass('ui-corner-all').attr({'aria-selected':'false','tabindex':'-1'});
        $('.ui-accordion-header .ui-icon').removeClass('ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-e');
        $('.ui-accordion-content').removeClass('ui-accordion-content-active').attr({'aria-expanded':'false','aria-hidden':'true'}).hide();
        $(this).hide();
        $('.open').show();
    });
    $('.ui-accordion-header').click(function () {
        $('.open').show();
        $('.close').show();
    });
});

http://jsfiddle.net/bigvax/hEApL/


As discussed in the jQuery UI forums, you should not use accordions for this.

If you want something that looks and acts like an accordion, that is fine. Use their classes to style them, and implement whatever functionality you need. Then adding a button to open or close them all is pretty straightforward. Example

HTML

By using the jquery-ui classes, we keep our accordions looking just like the "real" accordions.

<div id="accordion" class="ui-accordion ui-widget ui-helper-reset">
    <h3 class="accordion-header ui-accordion-header ui-helper-reset ui-state-default ui-accordion-icons ui-corner-all">
        <span class="ui-accordion-header-icon ui-icon ui-icon-triangle-1-e"></span>
        Section 1
    </h3>
    <div class="ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom">
        Content 1
    </div>
</div>?

Roll your own accordions

Mostly we just want accordion headers to toggle the state of the following sibling, which is it's content area. We have also added two custom events "show" and "hide" which we will hook into later.

var headers = $('#accordion .accordion-header');
var contentAreas = $('#accordion .ui-accordion-content ').hide();
var expandLink = $('.accordion-expand-all');

headers.click(function() {
    var panel = $(this).next();
    var isOpen = panel.is(':visible');

    // open or close as necessary
    panel[isOpen? 'slideUp': 'slideDown']()
        // trigger the correct custom event
        .trigger(isOpen? 'hide': 'show');

    // stop the link from causing a pagescroll
    return false;
});

Expand/Collapse All

We use a boolean isAllOpen flag to mark when the button has been changed, this could just as easily have been a class, or a state variable on a larger plugin framework.

expandLink.click(function(){
    var isAllOpen = $(this).data('isAllOpen');

    contentAreas[isAllOpen? 'hide': 'show']()
        .trigger(isAllOpen? 'hide': 'show');
});

Swap the button when "all open"

Thanks to our custom "show" and "hide" events, we have something to listen for when panels are changing. The only special case is "are they all open", if yes the button should be a "Collapse all", if not it should be "Expand all".

contentAreas.on({
    // whenever we open a panel, check to see if they're all open
    // if all open, swap the button to collapser
    show: function(){
        var isAllOpen = !contentAreas.is(':hidden');   
        if(isAllOpen){
            expandLink.text('Collapse All')
                .data('isAllOpen', true);
        }
    },
    // whenever we close a panel, check to see if they're all open
    // if not all open, swap the button to expander
    hide: function(){
        var isAllOpen = !contentAreas.is(':hidden');
        if(!isAllOpen){
            expandLink.text('Expand all')
            .data('isAllOpen', false);
        } 
    }
});?

Edit for comment: Maintaining "1 panel open only" unless you hit the "Expand all" button is actually much easier. Example


I found AlecRust's solution quite helpful, but I add something to resolve one problem: When you click on a single accordion to expand it and then you click on the button to expand, they will all be opened. But, if you click again on the button to collapse, the single accordion expand before won't be collapse.

I've used imageButton, but you can also apply that logic to buttons.

/*** Expand all ***/
$(".expandAll").click(function (event) {
    $('.accordion .ui-accordion-header:not(.ui-state-active)').next().slideDown();

    return false;
});

/*** Collapse all ***/
$(".collapseAll").click(function (event) {
    $('.accordion').accordion({
        collapsible: true,
        active: false
    });

    $('.accordion .ui-accordion-header').next().slideUp();

    return false;
});

Also, if you have accordions inside an accordion and you want to expand all only on that second level, you can add a query:

/*** Expand all Second Level ***/
$(".expandAll").click(function (event) {
    $('.accordion .ui-accordion-header:not(.ui-state-active)').nextAll(':has(.accordion .ui-accordion-header)').slideDown();

    return false;
});

I don't believe you can do this with an accordion since it's specifically designed preserve the property that at most one item will be opened. However, even though you say you don't want to re-implement accordion, you might be over estimating the complexity involved.

Consider the following scenario where you have a vertical stack of elements,

++++++++++++++++++++
+     Header 1     +
++++++++++++++++++++
+                  +
+      Item 1      +
+                  +
++++++++++++++++++++
+     Header 2     +
++++++++++++++++++++
+                  +
+      Item 2      +
+                  +
++++++++++++++++++++

If you're lazy you could build this using a table, otherwise, suitably styled DIVs will also work.

Each of the item blocks can have a class of itemBlock. Clicking on a header will cause all elements of class itemBlock to be hidden ($(".itemBlock").hide()). You can then use the jquery slideDown() function to expand the item below the header. Now you've pretty much implemented accordion.

To expand all items, just use $(".itemBlock").show() or if you want it animated, $(".itemBlock").slideDown(500). To hide all items, just use $(".itemBlock").hide().


Yes, it is possible. Put all div in separate accordion class as follows:

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery-ui.js"></script>

<script type="text/javascript">

        $(function () {
            $("input[type=submit], button")
        .button()
        .click(function (event) {
            event.preventDefault();
        });
            $("#tabs").tabs();
            $(".accordion").accordion({
                heightStyle: "content",

                collapsible: true,
                active: 0



            });
        });

function expandAll()
{
  $(".accordion").accordion({
                heightStyle: "content",

                collapsible: true,
                active: 0

            });

            return false;   
}

function collapseAll()
{
  $(".accordion").accordion({
                heightStyle: "content",

                collapsible: true,
                active: false



            });
            return false;
}
</script>



<div class="accordion">
  <h3>Toggle 1</h3>
  <div >
    <p>text1.</p>
  </div>
</div>
<div class="accordion">
  <h3>Toggle 2</h3>
  <div >
    <p>text2.</p>
  </div>
</div>
<div class="accordion">
  <h3>Toggle 3</h3>
  <div >
    <p>text3.</p>
  </div>
</div>

I second bigvax comment earlier but you need to make sure that you add

        jQuery("#jQueryUIAccordion").({ active: false,
                              collapsible: true });

otherwise you wont be able to open the first accordion after collapsing them.

    $('.close').click(function () {
    $('.ui-accordion-header').removeClass('ui-accordion-header-active ui-state-active ui-corner-top').addClass('ui-corner-all').attr({'aria-selected':'false','tabindex':'-1'});
    $('.ui-accordion-header .ui-icon').removeClass('ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-e');
    $('.ui-accordion-content').removeClass('ui-accordion-content-active').attr({'aria-expanded':'false','aria-hidden':'true'}).hide();
   }

try this one jquery-multi-open-accordion, might help you


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to jquery

How to make a variable accessible outside a function? Jquery assiging class to th in a table Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Getting all files in directory with ajax Bootstrap 4 multiselect dropdown Cross-Origin Read Blocking (CORB) bootstrap 4 file input doesn't show the file name Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource how to remove json object key and value.?

Examples related to jquery-ui

How to auto adjust the div size for all mobile / tablet display formats? jQuery not working with IE 11 JavaScript Uncaught ReferenceError: jQuery is not defined; Uncaught ReferenceError: $ is not defined Best Practice to Organize Javascript Library & CSS Folder Structure Change table header color using bootstrap How to get HTML 5 input type="date" working in Firefox and/or IE 10 Form Submit jQuery does not work Disable future dates after today in Jquery Ui Datepicker How to Set Active Tab in jQuery Ui How to use source: function()... and AJAX in JQuery UI autocomplete

Examples related to accordion

Bootstrap 3 collapse accordion: collapse all works but then cannot expand all while maintaining data-parent Bootstrap Accordion button toggle "data-parent" not working jQuery UI Accordion Expand/Collapse All How to use in jQuery :not and hasClass() to get a specific element without a class

Examples related to jquery-ui-accordion

jQuery UI Accordion Expand/Collapse All