javascriptjquerytoggleaccordionslidetoggle

How can I click to slide open divs in multiple instances independently of one another?


I have the following markup, below. Essentially, they are the same type of section with a heading, and some of them will have a panel that's initially invisible but will open when you click js-toggle. Not every .article will have the panels and triggers, and also some of them will have an external link.

I'm trying to make it so that when you click .js-toggle, only the panel in that .article will open and close, and the toggle element will have an .open class toggled. Opening one panel should not close panels in other articles.

<div class="article">
  <h2>Title here</h2>
  <p><span class="js-toggle">Open panel</span><a href="external link">Click me</a></p>
  <div class="panel">Some text here</div>
</div>

<div class="article">
  <h2>Title here</h2>
  <a href="external link">Click me</a>
</div>

<div class="article">
  <h2>Title here</h2>
  <p><span class="js-toggle">Open panel</span><a href="external link">Click me</a></p>
  <div class="panel">Some text here</div>
</div>

All my attempts so far have resulted in it either opening all the panels at once when you click one, or it only works in the first instance, or they work but then if one article doesn't have a sliding panel, then the following ones break.

I tried this both in vanilla js (which is preferable) as well as jquery (with slideToggle), but no luck. Any help would be greatly appreciated!


Solution

  • What you want is to limit the context where the script will be searching for .panel element. So can add click event to .js-toggle and start to search in HTML tree structure from there.

    In the example below it works this way:

    1. It starts from (this), (which stands for the clicked .js-toggle element)
    2. It searches for parent elements with .article class
    3. From there it searches for child elements with .panel class
    4. It calls slideToggle() on found element(s)

    Of course it is very dependent on the exact structure of the HTML, but for the markup mentioned above this jQuery should work.

    <script type="text/javascript">
      $(function() {
        $('.js-toggle').click(function() {
          $(this).parents('.article').find('.panel').slideToggle();
          return false;
        });
      });
    </script>
    
    <div class="article">
      <h2>Title here</h2>
      <p>
        <span class="js-toggle">Open panel</span>
        <a href="external link">Click me</a>
      </p>
      <div class="panel">Some text here</div>
    </div>
    
    <style media="screen">
      .panel {display: none;}
    </style>