Menu icon Foundation
Accordions - How do you animate opening and closing content?

Accordions: How do you animate the opening and closing of content sections?

accordionsanimationsclick

Accordions: How do you animate the opening and closing of content sections?

This post has been closed. No new replies can be added.

Christian Cruz almost 6 years ago

Bumping this thread.
I am trying to do the same and found this "solution":

$(".accordion").on("click", "dd", function (event) {
$("dd.active").find(".content").slideToggle("slow");
$(this).find(".content").slideToggle("slow");
})
});

from this thread:
http://foundation.zurb.com/forum/posts/536-accordion-click

BUT, it causes a weird bug.
It doesn't collapse the previous div when expanding the others.
See for yourself and let me know if it works for you.

James Dullaghan almost 6 years ago

Hey Christian,

To get the other content sections to close, you'll need to create a variable for the current target and add an if statement and find .content with class of active and remove or toggle that class

Something along the lines of:

var current = event.currentTarget
if (current.hasClass('active') {
  current.removeClass('active');
} 

Hopefully that will give you a headstart.

-James

Marco Messa almost 6 years ago

There's a simple way, because one line of the above code is wrong:

$(".accordion").on("click", "dd", function (event) {
$("dd.active").find(".content").slideToggle("slow");
$(this).find(".content").slideToggle("slow");
})
}); 

I got it changing 2nd line:

 $(".accordion").on("click", "dd", function (event) {
 $("div.active").slideToggle("slow");
 $(this).find(".content").slideToggle("slow");
 });

Oliver Marcetic almost 6 years ago

Has anyone found a solution for open/close animation?
I'm using F5 and closest thing that works is this but with bugs:

       $(".produkte-accordion").on("click", "dd", function (event) {
        $("div.active").slideToggle("slow");
        $(this).find(".content").slideToggle("slow");
      });

It opens, closes and opens again. And doesn't collapse the previous div when opening others.

Thanks!

Oliver Marcetic almost 6 years ago

Changing div.active to dd.active finally worked for me:

 $(".accordion").on("click", "dd", function (event) {
  $("dd.active").slideToggle("slow");
  $(this).find(".content").slideToggle("slow");
});

Nemanja Andrejevic almost 6 years ago

That code will cause that click on anywhere inside of "DD" element to close/open that "DD", as I wanted only click on first "A" element to cause this, I have changed the code to this:

      $(".accordion dd").on("click", "a:eq(0)", function (event)
      {
        $(".accordion dd div.content:visible").slideToggle("normal");
        $(this).parent().find(".content").slideToggle("normal");
      });

bofa almost 6 years ago

Thank you @Nemanja - excellent fix.

The class "active" remains on the last clicked dd. Any way to remove the class with a second click?

Nemanja Andrejevic almost 6 years ago

Yes, here is new improved version:

       $(".accordion dd").on("click", "a:eq(0)", function (event)
      {
        var dd_parent = $(this).parent();

        if(dd_parent.hasClass('active'))
          $(".accordion dd div.content:visible").slideToggle("normal");
        else
        {
          $(".accordion dd div.content:visible").slideToggle("normal");
          $(this).parent().find(".content").slideToggle("normal");
        }
      });

Andrew Saint almost 6 years ago

Is there a way to do this via CSS3 transitions?

bofa almost 6 years ago

Works beautifully! It is jumpy if class.active is preset on one of the panels on page load, but simply removing the active class allows the smooth functioning that a visitor would like. Very pleasing! Cheers!

Nemanja Andrejevic almost 6 years ago

@Andrew

As accordion uses "display: none" and "display: block" in CSS, you will not be able to implement CSS3 transitions AFAIK (http://www.w3.org/TR/css3-transitions/#animatable-properties).

But it you changed that behaviour to something like "width: 0" and "width: 5em", I think you could make it work.

Bernardo Medeiros Gomes over 5 years ago

Does this works on Foundation 5?

Steven McCoy over 5 years ago

I ran into the same issue, and wrote a fairly simple jQuery plugin to get this working. The plugin has default options, while also allowing overrides via the data-options attribute.

Tested on Foundation 5.

(function($) {
  $.fn.accordionAnimated = function() {

    var
      $accordion = this,
      $items = $accordion.find('> dd'),
      $targets = $items.find('.content'),
      options = {
        active_class : 'active',  // class for items when active
        multi_expand: false,    // whether mutliple items can expand
        speed : 500,        // speed of animation
        toggleable: true      // setting to false only closes accordion panels when another is opened
      }
    ;

    $.extend(options, Foundation.utils.data_options($accordion));

    $items.each(function(i) {
      $(this).find('a:eq(0)').on('click.accordion', function() {
        if(!options.toggleable && $items.eq(0).hasClass(options.active_class)) {
          return;
        }

        $targets.eq(i)
          .stop(true, true)
          .slideToggle(options.speed);

        if(!options.multi_expand) {
          $targets.not(':eq('+i+')')
            .stop(true, true)
            .slideUp(options.speed);
        }
      });
    });
  };
}(jQuery)); 

The plugin is easy to invoke:

$('.accordion').accordionAnimated(); 

Neil Haskins over 5 years ago

I would suggest a slight change to the above. Currently, if multi_expand is false then clicking on an accordion link in any accordion will close all other accordian .content on the page.
So as to scope the closeing of other panels to only within the accordion being clicked, change

if(!options.multi_expand) {
$targets.not(':eq('+i+')')

to

if(!options.multi_expand) {
$targets.eq(i).parent().siblings().children('.content').not(':eq('+i+')')

Perhaps that could be optimized somehow, but it gets the job done anyway :)

Eli Lev over 5 years ago

This works perfect for me

<div class="row">
        <div class="large-10 small-12 small-centered columns text-center">
        <dl class="accordion" data-accordion>
          <dd>
            <a href="#panel1"><h4>// title goes here</h4></a>
            <div id="panel1" class="content text-justify">
              // content goes her

            </div>
          </dd>
          <dd>
            <a href="#panel2"><h4>// title goes here </h4> </a>
            <div id="panel2" class="content text-justify">
              // content goes here
            </div>
          </dd>
          <dd>
            <a href="#panel3"><h4>// title goes here </h4> </a>
            <div id="panel3" class="content text-justify">
             // content goes her
            </div>
          </dd>
        </dl>        
        </div>
    </div>
 $(".accordion dd").on("click", "a:eq(0)", function (event)
      {
        var dd_parent = $(this).parent();

        if(dd_parent.hasClass('active'))
          $(".accordion dd div.content:visible").slideToggle("normal");
        else
        {
          $(".accordion dd div.content:visible").slideToggle("normal");
          $(this).parent().find(".content").slideToggle("normal");
        }
      });

Tobias Malikowski over 5 years ago

Hi there,

I'm trying to get the Stevens plugin working for a multilevel accordion.
The accordion is already working, but i can't get the plugin to do the sliding on all sub accordions.

It only works on the parent accordion and the first child...

Here's a fiddle, so you can get the idea: http://jsfiddle.net/Sbt75/514/

Any help would be very nice.

Thank you guys :)

Marc McGee about 5 years ago

These are some excellent tips. Both of Nemanja Andrejevic' are working for me. Though I do like Stevens approach that permits inserting of options.

Anyone know how to get the panels to perhaps scroll to top when opened, or at least get content into view. Longer content sections on my page are scolling off the bottom of the screen. Awkward the the user must click and then scroll to finish reading or to click other items.

Not sure which is worse or less user friendly though: Click and having to scroll, or having stuff automatically jump and scroll to top while your eyes are trying to focus on the content.

Michael C. almost 5 years ago

It's possible to animate these purely through CSS, although there are a couple of caveats to take into consideration:

First, expanded panels will need to be assigned an arbitrary max-height. My advice is to use something like max-height: 80vh (100vh = the full viewport height) and apply an overflow-y: auto.

Secondly, because we're animating the max-height property and not the automatically-calculated height (which we can't animate), any accordions that are shorter than that max-height will take proportionately less time to open up. For example, if your accordion's content makes it 200px tall, the max-height is set to 400px, and the transition duration is set to 1 second, the accordion's content will be fully revealed after 0.5 seconds.

On to the SCSS code:

.accordion
{
  .accordion-navigation
  {
    .content
    {
      display: block;
      max-height: 0;
      overflow-y: auto;
      // leave the top and bottom padding at 0, have the sides match the .active element's padding value below
      padding: rem-calc(0 16);
      // change as desired but the transition needs to cover both max-height and padding; this is how long the panel takes to close
      transition: ease 0.4s all;
      &.active
      {
        // change as desired
        max-height: 80vh;
        // change as desired
        padding: rem-calc(16);
        // change as desired; this is how long the panel takes to open
        transition: ease 0.4s all;
        // change as desired, but for best results keep at around half the other transition durations
        transition-delay: 0.2s;
      }
    }
  }
}

Obviously vendor-prefix the appropriate CSS rules or just use Compass or something.

Luis del Rio almost 5 years ago

Here's another option if you don't wan´t the active ones to toggle off and first line sets the pre-active one to be animated (commented line toggles the active one)

$(".content.active").css('display','block');
        $(".accordion").on("click", "dd", function (event) {
          if($(this).is('.active')) {
            // $("dd.active").find(".content").slideToggle();
             var self = $(this);
             setTimeout(function() {
               self.addClass('active').find(".content").addClass('active');
             },10);
          } else {
            $("dd.active").find(".content").slideToggle();
            $(this).find(".content").slideToggle();
          }
        });