Blog

Construct an Animated JavaScript Accordion Element, With Overlapping Panels

On this new tutorial, we’ll discover ways to construct an animated JavaScript accordion element with overlapping panels.

We received’t focus a lot on accessibility on this tutorial, so exploring find out how to make this element extra accessible could be a sound subsequent step.

Our Accordion Element

Right here’s what we will create (click on on a panel to check the habits):

1. Start With the Web page Markup

Inside a container, we’ll place an inventory of panels.

Every panel may have a title and content material. Throughout the title, we’ll add a Shut button from the place we are able to shut the energetic panel.

Right here’s the required construction:

1 class=“accordion-wrapper”>
2

    3

  • 4 class=“accordion-title”>

    5 class=“accordion-content”>
    6 class=“inside”>

    7

    8

    9

  • 10 class=“accordion-title”>

    11 class=“accordion-content”>
    12 class=“inside”>

    13

    14

    15

  • 16 class=“accordion-title”>

    17 class=“accordion-content”>
    18 class=“inside”>

    19

    20

    21

  • 22 class=“accordion-title”>

    23 class=“accordion-content”>
    24 class=“inside”>

    25

    26

    27

    28

    Preliminary Accordion State/Lively Gadgets

    By default, all panels might be collapsed.

    Our accordion with collapsed panelsOur accordion with collapsed panels

    To forestall this habits, we’ve to assign the energetic class to a number of panels like this: 

    1

      2 class=“energetic”>

      3

      Our accordion with an expanded panelOur accordion with an expanded panelOur accordion with an expanded panel

      A number of Open Panels

      There’s additionally the choice to have a couple of panel open concurrently with out one collapsing when the opposite is open. To allow this, we must always add the data-multiple=”true” attribute to the accordion wrapper like this:

      1 class=“accordion-wrapper” data-multiple=“true”>

      Our accordion with multiple panels being open at the same timeOur accordion with multiple panels being open at the same timeOur accordion with multiple panels being open at the same time

      2. Add the CSS

      Let’s now consider the important thing kinds—a lot of the different kinds aren’t something particular, so let’s go away them for now:

      • To make the panels overlap and create a special accordion format in comparison with the usual ones, we’ll give them a destructive prime margin and an equal backside padding. Just for the primary and final objects, we’ll cancel the highest margin and backside padding respectively. 
      • To cover the content material of every panel, we’ll give them top: 0 and overflow: hidden. Then, as we’ll see later, by way of JavaScript, we’ll recalculate their top and reveal them easily. Simply, be aware that we’ll additionally use top: 0 !essential to reset the peak to 0 and override the JavaScript kinds for a beforehand energetic panel. 
      • To open the modal, the entire panel space might be clickable. To make it clear, we’ll assign cursor: pointer to all panels. Quite the opposite, when a panel is open, we are able to shut it solely by way of the shut button. At this second, solely this button may have cursor: pointer whereas the panel may have cursor: default.

      Right here’s part of the required kinds:

      1/*CUSTOM STYLES HERE*/
      2
      3.accordion-wrapper li {
      4 padding: 0 20px 100px;
      5 cursor: pointer;
      6 border-top-left-radius: var(–accordion-radius);
      7 border-top-right-radius: var(–accordion-radius);
      8 background: var(–accordion-bg-color);
      9 transition: all 0.2s ease-out;
      10}
      11
      12.accordion-wrapper li:not(:first-child) {
      13 margin-top: -100px;
      14 border-top: 2px stable var(–light-cyan);
      15}
      16
      17.accordion-wrapper li:nth-last-child(2),
      18.accordion-wrapper li:last-child {
      19 border-bottom-left-radius: var(–accordion-radius);
      20 border-bottom-right-radius: var(–accordion-radius);
      21}
      22
      23.accordion-wrapper li:last-child {
      24 padding-bottom: 0;
      25}
      26
      27.accordion-wrapper:not([data-multiple=“true”]) li.energetic {
      28 border-top-color: var(–accordion-active-bg-color);
      29}
      30
      31.accordion-wrapper li.energetic {
      32 cursor: default;
      33 coloration: var(–white);
      34 background: var(–accordion-active-bg-color);
      35}
      36
      37.accordion-wrapper li:not(.energetic) .accordion-content {
      38 top: 0 !essential;
      39}
      40
      41.accordion-wrapper .accordion-content {
      42 top: 0;
      43 overflow: hidden;
      44 transition: top 0.3s;
      45}
      46
      47.accordion-wrapper .inside {
      48 padding-bottom: 40px;
      49}
      50
      51@media (min-width: 700px) {
      52 .accordion-wrapper li {
      53 padding-left: 60px;
      54 padding-right: 60px;
      55 }
      56
      57 .accordion-wrapper .inside {
      58 max-width: 85%;
      59 }
      60}

      3. Add the JavaScript

      The way in which we’ll animate every panel and obtain a slide impact just like jQuery’s slideToggle() perform is by benefiting from the scrollHeight property.

      This property measures the peak of a component’s content material, together with content material not seen on the display on account of overflow. In our case, we’ll must calculate that worth for the .accordion-content components which have top: 0 and overflow: hidden by default.

      When DOM Prepared

      As a primary motion, when the DOM is prepared, we’ll verify if there are any energetic panels, and if that’s the case, we’ll set the peak for the .accordion-content component of every energetic panel equal to its scrollHeight property worth.

      Right here’s the associated JavaScript code:

      1const activeItems = accordionWrapper.querySelectorAll(li.energetic);
      2
      3if (activeItems) {
      4 activeItems.forEach(perform (merchandise) {
      5 const content material = merchandise.querySelector(.accordion-content);
      6 content material.type.top = `${content material.scrollHeight}px`;
      7 });
      8}

      Toggle Accordion Panels

      Subsequent, every time we click on on a panel, we’ll do the next issues:

      1. Test if we clicked on the shut button. If that occurs and the panel is open, we’ll shut it by eradicating the energetic class and ignoring all the subsequent steps.
      2. Test if we’ve set the choice to have a number of panels open collectively. If that isn’t the case and there’s an energetic panel, we’ll shut it.
      3. Add the energetic class to that panel.
      4. Set the peak for the .accordion-content component of this panel equal to its scrollHeight property worth.

      Right here’s the JavaScript code that implements all that habits:

      1const accordionWrapper = doc.querySelector(.accordion-wrapper);
      2const objects = accordionWrapper.querySelectorAll(li);
      3const multiple_open = accordionWrapper.dataset.a number of;
      4const ACTIVE_CLASS = energetic;
      5
      6objects.forEach(perform (merchandise) {
      7 merchandise.addEventListener(click on, perform (e) {
      8 // 1
      9 const goal = e.goal;
      10 if (
      11 (goal.tagName.toLowerCase() === button || goal.closest(button)) &&
      12 merchandise.classList.incorporates(ACTIVE_CLASS)
      13 ) {
      14 merchandise.classList.take away(ACTIVE_CLASS);
      15 return;
      16 }
      17
      18 // 2
      19 if (
      20 true !== multiple_open &&
      21 doc.querySelector(.accordion-wrapper li.energetic)
      22 ) {
      23 doc
      24 .querySelector(.accordion-wrapper li.energetic)
      25 .classList.take away(ACTIVE_CLASS);
      26 }
      27
      28 // 3
      29 merchandise.classList.add(ACTIVE_CLASS);
      30
      31 // 4
      32 const content material = merchandise.querySelector(.accordion-content);
      33 content material.type.top = `${content material.scrollHeight}px`;
      34 });
      35});

      Conclusion

      Finished! I hope you loved the JavaScript accordion we constructed and realized one or two new issues.

      Earlier than closing, let’s recall our essential creation right this moment:

      As at all times, thanks quite a bit for studying!