Search code examples
javascripthtmljquerygsap

Accordion not working correctly (active states not being applied for each parent instance)


I have accordions which on click, grow in height and also changes the image to what is relevant to that section (this is done based on data-id).

Here are the requirements that I'm trying to achieve:

  • Each accordion group is contained within .accordionRepeater__wrapper and for each instance of that class, I'm trying to get the first .accordionCard. to have the open state.
  • Only have the first .accordionCard in each accordionRepeater__wrapper open on page load, so the user can see some content by default.
  • Only have one .accordionCard in each accordionRepeater__wrapper open at a time (user cannot have two or more accordionCard open in a accordionRepeater__wrapper at one time).

Currently results:

  • The first .accordionCard in the first .accordionRepeater__wrapper has the class of .accordionCard--open on page load, but doesn't show the content for it.
  • The first instance of .accordionCard in the second .accordionRepeater__wrapper doesn't have the class of .accordionCard--open and doesn't show the image. Only when I click on it does the image and content show.

See my attempt here:

$(function() {

  const card = $(".accordionCard");
  const expand_icon = $(".accordionCard__expand");


  // open first accordion in each .accordionRepeater__wrapper by default
  $(".accordionCard:first accordionCard__expand").addClass("expanded");
  $(".accordionCard:first").addClass("accordionCard--open");
  $(".accordionRepeater__image:first").addClass("d-block");


  card.click(function() {
    var hidden = $(this).children(".accordionCard__body--hidden");

    // only have one card open at a time
    expand_icon.removeClass("expanded");
    card.removeClass("accordionCard--open");

    /* CLOSE CARD */

    if ($(this).hasClass("accordionCard--open")) {
      TweenMax.to(hidden, 0.3, {
        height: 0,
        immediateRender: false,
        ease: Power1.easeOut
      });
      $(this).removeClass("accordionCard--open");
      $(this).find(expand_icon).removeClass("expanded");
    }

    /* OPEN CARD */
    else {
      TweenMax.set(hidden, {
        height: "auto"
      });
      TweenMax.from(hidden, 1, {
        height: 0,
        immediateRender: false,
        ease: Back.easeOut
      });
      $(this).addClass("accordionCard--open");
      $(this).find(expand_icon).addClass("expanded");

      // show correct image
      var id = $(this).attr('data-item');
      $(".accordionRepeater__image").removeClass("d-block");
      $(".accordionRepeater__image[data-item='" + id + "']").addClass("d-block");
    }

    /* END */

  });



});
:root {
  --green: #089F84;
  --white-2: #F7F7F7;
  --black-2: #2C3645;
}

.accordionRepeater {
  padding: 130px 0 156px 0;
}

.accordionRepeater__wrapper {
  padding-bottom: 140px;
}

.accordionRepeater__wrapper:last-child {
  padding-bottom: 0;
}

.accordionRepeater__row--even {
  flex-direction: row-reverse;
}

.accordionRepeater .accordionCard {
  margin: 13px 0;
  cursor: pointer;
  padding-left: 26px;
}

.accordionRepeater .accordionCard:hover .accordionCard__body-label {
  color: var(--green);
}

.accordionRepeater .accordionCard--open {
  background-color: var(--white-2);
  padding: 36px 48px 45px 26px;
  border-radius: 10px;
}

.accordionRepeater .accordionCard__expand {
  position: absolute;
}

.accordionRepeater .accordionCard__expand:before,
.accordionRepeater .accordionCard__expand:after {
  content: "";
  display: block;
  position: absolute;
  top: 50%;
  transform: translate(0px, 10px);
  right: 0;
  margin: 0 0 -8px;
  background-color: var(--green);
  border-radius: 5px;
}

.accordionRepeater .accordionCard__expand:before {
  right: 8px;
  width: 3px;
  height: 16px;
  transition: all 0.5s ease;
  margin-top: -7.5px;
}

.accordionRepeater .accordionCard__expand:after {
  right: 1px;
  width: 16px;
  height: 3px;
  margin-top: -1.5px;
}

.accordionRepeater .accordionCard__expand.expanded:before,
.accordionRepeater .accordionCard__expand.expanded:after {
  background-color: var(--black-2);
}

.accordionRepeater .accordionCard__expand.expanded:before {
  height: 0;
  margin-top: 0;
}

.accordionRepeater .accordionCard__body {
  margin-left: 20px;
}

.accordionRepeater .accordionCard__body--visible {
  width: 100%;
}

.accordionRepeater .accordionCard__body--hidden {
  overflow: hidden;
  height: 0;
}

.accordionRepeater .accordionCard__body-label {
  transition: all 0.5s ease;
  margin-left: 20px;
}

.accordionRepeater .accordionCard__body-copy {
  padding: 24px 0 17px 0;
}

.accordionRepeater .accordionCard__body-link {
  transition: none;
}

.accordionRepeater__image {
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

<div class="accordionRepeater">

  <div class="container">

    <!-----------
     -- FIRST SET
     -------------->

    <div class="accordionRepeater__wrapper">
      <div class="row justify-content-between align-items-center accordionRepeater__row accordionRepeater__row--odd">
        <div class="col-12 col-lg-6">
          <div class="accordionRepeater__text">

            <div class="accordionRepeater__text-accordion">

              <!-- CARD 1 -->

              <div class="accordionCard position-relative d-flex flex-column" data-item="1">
                <div class="accordionCard__body">
                  <div class="accordionCard__expand"></div>
                  <span class="accordionCard__body-label d-block">Lorum</span>
                </div>
                <div class="accordionCard__body--hidden">
                  <div class="accordionCard__body-copy">
                    <p>Lorum ipsum</p>
                  </div>
                </div>
              </div>

              <!-- CARD 2 -->

              <div class="accordionCard position-relative d-flex flex-column" data-item="2">
                <div class="accordionCard__body">
                  <div class="accordionCard__expand"></div>
                  <span class="accordionCard__body-label d-block">Lorum 2</span>
                </div>
                <div class="accordionCard__body--hidden">
                  <div class="accordionCard__body-copy">
                    <p>Lorum ipsum 2</p>
                  </div>
                </div>
              </div>

              <!-- CARD END -->

            </div>
          </div>
        </div>


        <div class="col-12 col-lg-6">
          <div class="accordionRepeater__graphic">
            <img class="accordionRepeater__image" src="https://picsum.photos/500" alt="placeholder-graphic" loading="lazy" style="max-width: 100%; height: auto;" data-item="1">
            <img class="accordionRepeater__image" src="https://picsum.photos/550" alt="placeholder-graphic" loading="lazy" style="max-width: 100%; height: auto;" data-item="2">
            <img class="accordionRepeater__image" src="https://picsum.photos/500" alt="placeholder-graphic" loading="lazy" style="max-width: 100%; height: auto;" data-item="3">
          </div>
        </div>

      </div>
    </div>

    <!-----------
    -- FIRST SET END
    -------------->

    <!-----------
     -- SECOND SET
     -------------->

    <div class="accordionRepeater__wrapper">
      <div class="row justify-content-between align-items-center accordionRepeater__row accordionRepeater__row--even">
        <div class="col-12 col-lg-6">
          <div class="accordionRepeater__text">

            <div class="accordionRepeater__text-accordion">

              <!-- CARD 1 -->

              <div class="accordionCard position-relative d-flex flex-column" data-item="1">
                <div class="accordionCard__body">
                  <div class="accordionCard__expand"></div>
                  <span class="accordionCard__body-label d-block">Lorum</span>
                </div>
                <div class="accordionCard__body--hidden">
                  <div class="accordionCard__body-copy">
                    <p>Lorum ipsum</p>
                  </div>
                </div>
              </div>

              <!-- CARD END -->

            </div>
          </div>
        </div>


        <div class="col-12 col-lg-6">
          <div class="accordionRepeater__graphic">
            <img class="accordionRepeater__image" src="https://picsum.photos/500" alt="placeholder-graphic" loading="lazy" style="max-width: 100%; height: auto;" data-item="1">
          </div>
        </div>

      </div>
    </div>

    <!-----------
    -- SECOND SET END
    -------------->

  </div>
</div>


Solution

  • You are not expanding the accordions at the start. You are doing it only on click.
    Also the method needs to handle expansion and close at set level. And not globally.

    It can be done like this:

    $(function() {
      const card = $('.accordionCard');
      const expand_icon = $('.accordionCard__expand');
    
      $('.accordionCard:first-child').each((i, a) => toggleAc(a));
    
      card.click(function() {
        toggleAc(this);
      });
    
      // expand/close given accordions
      function toggleAc(acdn) {
        var hidden = $(acdn).children('.accordionCard__body--hidden');
        const isOpen = $(acdn).hasClass('accordionCard--open');
    
        /* CLOSE CARD */
        if (isOpen) {
          return;  // this ensures that at least one will remain open all the time
          /*TweenMax.to(hidden, 0.3, {
            height: 0,
            immediateRender: false,
            ease: Power1.easeOut,
          });
          $(acdn).removeClass('accordionCard--open');
          $(acdn).find(expand_icon).removeClass('expanded');
          */
          
        } else {
          // close previous card in the same set
          const parent = $(acdn).parent();
          const expandedCard = parent.find('.accordionCard--open');
          const expandedIcon = parent.find('.expanded');
          const expandedCardHidden = expandedCard.children('.accordionCard__body--hidden');
          TweenMax.to(expandedCardHidden, 0.3, {
            height: 0,
            immediateRender: false,
            ease: Power1.easeOut,
          });
          expandedIcon.removeClass('expanded');
          expandedCard.removeClass('accordionCard--open');
    
          /* OPEN CARD */
          TweenMax.set(hidden, {
            height: 'auto',
          });
          TweenMax.from(hidden, 1, {
            height: 0,
            immediateRender: false,
            ease: Back.easeOut,
          });
          $(acdn).addClass('accordionCard--open');
          $(acdn).find(expand_icon).addClass('expanded');
    
          // show correct image
          var id = $(acdn).attr('data-item');
          const grandParent = parent.parent().parent().parent();
          grandParent.find('.accordionRepeater__image').removeClass('d-block');
          grandParent
            .find(".accordionRepeater__image[data-item='" + id + "']")
            .addClass('d-block');
        }
    
        /* END */
      }
    });
    :root {
      --green: #089f84;
      --white-2: #f7f7f7;
      --black-2: #2c3645;
    }
    
    .accordionRepeater {
      padding: 130px 0 156px 0;
    }
    
    .accordionRepeater__wrapper {
      padding-bottom: 140px;
    }
    
    .accordionRepeater__wrapper:last-child {
      padding-bottom: 0;
    }
    
    .accordionRepeater__row--even {
      flex-direction: row-reverse;
    }
    
    .accordionRepeater .accordionCard {
      margin: 13px 0;
      cursor: pointer;
      padding-left: 26px;
    }
    
    .accordionRepeater .accordionCard:hover .accordionCard__body-label {
      color: var(--green);
    }
    
    .accordionRepeater .accordionCard--open {
      background-color: var(--white-2);
      padding: 36px 48px 45px 26px;
      border-radius: 10px;
    }
    
    .accordionRepeater .accordionCard__expand {
      position: absolute;
    }
    
    .accordionRepeater .accordionCard__expand:before,
    .accordionRepeater .accordionCard__expand:after {
      content: '';
      display: block;
      position: absolute;
      top: 50%;
      transform: translate(0px, 10px);
      right: 0;
      margin: 0 0 -8px;
      background-color: var(--green);
      border-radius: 5px;
    }
    
    .accordionRepeater .accordionCard__expand:before {
      right: 8px;
      width: 3px;
      height: 16px;
      transition: all 0.5s ease;
      margin-top: -7.5px;
    }
    
    .accordionRepeater .accordionCard__expand:after {
      right: 1px;
      width: 16px;
      height: 3px;
      margin-top: -1.5px;
    }
    
    .accordionRepeater .accordionCard__expand.expanded:before,
    .accordionRepeater .accordionCard__expand.expanded:after {
      background-color: var(--black-2);
    }
    
    .accordionRepeater .accordionCard__expand.expanded:before {
      height: 0;
      margin-top: 0;
    }
    
    .accordionRepeater .accordionCard__body {
      margin-left: 20px;
    }
    
    .accordionRepeater .accordionCard__body--visible {
      width: 100%;
    }
    
    .accordionRepeater .accordionCard__body--hidden {
      overflow: hidden;
      height: 0;
    }
    
    .accordionRepeater .accordionCard__body-label {
      transition: all 0.5s ease;
      margin-left: 20px;
    }
    
    .accordionRepeater .accordionCard__body-copy {
      padding: 24px 0 17px 0;
    }
    
    .accordionRepeater .accordionCard__body-link {
      transition: none;
    }
    
    .accordionRepeater__image {
      display: none;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous" />
    
    <div class="accordionRepeater">
      <div class="container">
        <!-----------
         -- FIRST SET
         -------------->
    
        <div class="accordionRepeater__wrapper">
          <div class="row justify-content-between align-items-center accordionRepeater__row accordionRepeater__row--odd">
            <div class="col-12 col-lg-6">
              <div class="accordionRepeater__text">
                <div class="accordionRepeater__text-accordion">
                  <!-- CARD 1 -->
    
                  <div class="accordionCard position-relative d-flex flex-column" data-item="1">
                    <div class="accordionCard__body">
                      <div class="accordionCard__expand"></div>
                      <span class="accordionCard__body-label d-block">Lorum</span>
                    </div>
                    <div class="accordionCard__body--hidden">
                      <div class="accordionCard__body-copy">
                        <p>Lorum ipsum</p>
                      </div>
                    </div>
                  </div>
    
                  <!-- CARD 2 -->
    
                  <div class="accordionCard position-relative d-flex flex-column" data-item="2">
                    <div class="accordionCard__body">
                      <div class="accordionCard__expand"></div>
                      <span class="accordionCard__body-label d-block">Lorum 2</span>
                    </div>
                    <div class="accordionCard__body--hidden">
                      <div class="accordionCard__body-copy">
                        <p>Lorum ipsum 2</p>
                      </div>
                    </div>
                  </div>
    
                  <!-- CARD END -->
                </div>
              </div>
            </div>
    
            <div class="col-12 col-lg-6">
              <div class="accordionRepeater__graphic">
                <img class="accordionRepeater__image" src="https://picsum.photos/500" alt="placeholder-graphic" loading="lazy" style="max-width: 100%; height: auto;" data-item="1" />
                <img class="accordionRepeater__image" src="https://picsum.photos/550" alt="placeholder-graphic" loading="lazy" style="max-width: 100%; height: auto;" data-item="2" />
                <img class="accordionRepeater__image" src="https://picsum.photos/500" alt="placeholder-graphic" loading="lazy" style="max-width: 100%; height: auto;" data-item="3" />
              </div>
            </div>
          </div>
        </div>
    
        <!-----------
        -- FIRST SET END
        -------------->
    
        <!-----------
         -- SECOND SET
         -------------->
    
        <div class="accordionRepeater__wrapper">
          <div class="row justify-content-between align-items-center accordionRepeater__row accordionRepeater__row--even">
            <div class="col-12 col-lg-6">
              <div class="accordionRepeater__text">
                <div class="accordionRepeater__text-accordion">
                  <!-- CARD 1 -->
    
                  <div class="accordionCard position-relative d-flex flex-column" data-item="1">
                    <div class="accordionCard__body">
                      <div class="accordionCard__expand"></div>
                      <span class="accordionCard__body-label d-block">Lorum</span>
                    </div>
                    <div class="accordionCard__body--hidden">
                      <div class="accordionCard__body-copy">
                        <p>Lorum ipsum</p>
                      </div>
                    </div>
                  </div>
    
                  <!-- CARD END -->
                </div>
              </div>
            </div>
    
            <div class="col-12 col-lg-6">
              <div class="accordionRepeater__graphic">
                <img class="accordionRepeater__image" src="https://picsum.photos/500" alt="placeholder-graphic" loading="lazy" style="max-width: 100%; height: auto;" data-item="1" />
              </div>
            </div>
          </div>
        </div>
    
        <!-----------
        -- SECOND SET END
        -------------->
      </div>
    </div>