Saltyy
Saltyy

Reputation: 23

How to have a default tab open in this accordion and have it close the tab when another is opened?

I'm not very good at javascript and I am just using the basic code from w3. I'm trying to put an accordion on my website that lists some of the services in categories and I would like one tab to always be expanded.

Here is my current code:

var acc = document.getElementsByClassName("accordion");
var i;

for (i = 0; i < acc.length; i++) {
  acc[i].onclick = function() {
    this.classList.toggle("active");
    var panel = this.nextElementSibling;
    if (panel.style.maxHeight) {
      panel.style.maxHeight = null;
    } else {
      panel.style.maxHeight = panel.scrollHeight + "px";
    }
  }
}
/* Style the buttons that are used to open and close the accordion panel */

button.accordion {
  background-color: #3bb7df;
  color: #fff;
  cursor: pointer;
  padding: 0 20px;
  line-height: 54px;
  width: 100%;
  text-align: left;
  border: none;
  outline: none;
  transition: 0.4s;
  font-size: 17px;
  font-weight: 300;
}


/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */

button.accordion.active,
button.accordion:hover {
  background-color: #2894b7;
}

button.accordion:after {
  content: '+';
  font-size: 20px;
  font-weight: 400;
  color: #fff;
  border: none;
  float: right;
  margin-left: 5px;
  text-shadow: none;
}

button.accordion.active:after {
  content: "–";
}


/* Style the accordion panel. Note: hidden by default */

div.panel {
  padding: 0;
  background-color: #f5f5f5;
  border: none;
  border-radius: 0px;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
}

div.panel li {
  list-style: none;
  border-top: solid 1px #ddd;
}

div.panel li:hover {
  background: #e0e0e0;
}

div.panel a {
  color: #1d1d1d;
  font-size: 15px;
  display: block;
  padding: 12px 0;
}

div.panel i.fa-angle-right {
  padding: 0 15px;
}
<button class="accordion">Section 1</button>
<div class="panel">
  <ul>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 1</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 2</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 3</a></li>
  </ul>
</div>

<button class="accordion">Section 2</button>
<div class="panel">
  <ul>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 1</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 2</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 3</a></li>
  </ul>
</div>

<button class="accordion">Section 3</button>
<div class="panel">
  <ul>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 1</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 2</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 3</a></li>
  </ul>
</div>

All of the default code and be found on the w3 site for the accordion.

I want the first tab to be open by default, and then if another tab is opened, close the other open tab.

Thanks.

Upvotes: 2

Views: 4634

Answers (3)

Trent
Trent

Reputation: 4306

Opening first tab by default

To open the first tab (or any other) by default, simply invoke the click() method on the desired accordion index. This can be done at the end of your JavaScript:

acc[0].click(); // <-- Invoke the onClick for the first tab.

Always keep one tab expanded

To keep one accordion tab open at all times, radio button style, you'll need to save a reference to the last clicked accordion item, then perform some logic to close it before opening the new accordion menu.

See below for the working example.


Complete Example

I've cleaned up your code a bit by moving the operations to seperate functions, and including the opening first tab by default and always keep one tab expanded changes.

There is an alwaysOneOpen variable on line 4 of the JS that you can toggle to change the behavior. Currently it is true, which stops you from having all tabs closed. If you change this to false, you'll be able to close the tab by clicking on it.

var acc = document.getElementsByClassName("accordion");
var i;
var last;
var alwaysOneOpen = true;

for (i = 0; i < acc.length; i++) {
  acc[i].onclick = function() {
    // If the same accordion was clicked, toggle it
    if (last === this && !alwaysOneOpen) {
      toggleAccordion(last);
    } else {
      // If another accordion was open, close it
      if (last) {
        closeAccordion(last);
      }
      // Open clicked accordion
      last = this;
      openAccordion(last);
    }
  };
}

var closeAccordion = function(acc) {
  acc.classList.remove("active");
  var panel = acc.nextElementSibling;
    panel.classList.remove("active");
  panel.style.maxHeight = null;
}

var openAccordion = function(acc) {
  acc.classList.add("active");
  var panel = acc.nextElementSibling;
    panel.classList.add("active");
  panel.style.maxHeight = panel.scrollHeight + "px";
}

var toggleAccordion = function(acc) {
  last.classList.toggle("active");
  var panel = last.nextElementSibling;
  panel.classList.toggle("active");
  if (panel.style.maxHeight) {
    panel.style.maxHeight = null;
  } else {
    panel.style.maxHeight = panel.scrollHeight + "px";
  }
};

last = acc[0];
toggleAccordion(last);
/* Style the buttons that are used to open and close the accordion panel */

button.accordion {
  background-color: #3bb7df;
  color: #fff;
  cursor: pointer;
  padding: 0 20px;
  line-height: 54px;
  width: 100%;
  text-align: left;
  border: none;
  outline: none;
  transition: 0.4s;
  font-size: 17px;
  font-weight: 300;
}


/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */

button.accordion.active,
button.accordion:hover {
  background-color: #2894b7;
}

button.accordion:after {
  content: '+';
  font-size: 20px;
  font-weight: 400;
  color: #fff;
  border: none;
  float: right;
  margin-left: 5px;
  text-shadow: none;
}

button.accordion.active:after {
  content: "–";
}


/* Style the accordion panel. Note: hidden by default */

div.panel {
  padding: 0;
  background-color: #f5f5f5;
  border: none;
  border-radius: 0px;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
}

div.panel li {
  list-style: none;
  border-top: solid 1px #ddd;
}

div.panel li:hover {
  background: #e0e0e0;
}

div.panel a {
  color: #1d1d1d;
  font-size: 15px;
  display: block;
  padding: 12px 0;
}

div.panel i.fa-angle-right {
  padding: 0 15px;
}
   

 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="accordion">Section 1</button>
<div class="panel">
  <ul>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 1</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 2</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 3</a></li>
  </ul>
</div>

<button class="accordion">Section 2</button>
<div class="panel">
  <ul>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 1</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 2</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 3</a></li>
  </ul>
</div>

<button class="accordion">Section 3</button>
<div class="panel">
  <ul>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 1</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 2</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 3</a></li>
  </ul>
</div>

Upvotes: 2

happymacarts
happymacarts

Reputation: 2595

You did not specify if a jQuery solution was acceptable but I provided one here. I can rework to get vanilla JS if that is what you need.

Also note I simplified the logic for the 'scrollHeight' by using the inherit attribute of max-height

$(document).ready(function() {
  $('.accordion').on('click', function() {
  
    //remove 'active' from all items first
    $('.accordion').removeClass('active');
    
    // now add 'active' to the one clicked
    $(this).toggleClass('active');
  })

  //change to whichever number you want active on load
  $('.accordion:nth-of-type(2)').click();

})
/* Style the buttons that are used to open and close the accordion panel */

button.accordion {
  background-color: #3bb7df;
  color: #fff;
  cursor: pointer;
  padding: 0 20px;
  line-height: 54px;
  width: 100%;
  text-align: left;
  border: none;
  outline: none;
  transition: 0.4s;
  font-size: 17px;
  font-weight: 300;
}


/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */

button.accordion.active,
button.accordion:hover {
  background-color: #2894b7;
}

button.accordion:after {
  content: '+';
  font-size: 20px;
  font-weight: 400;
  color: #fff;
  border: none;
  float: right;
  margin-left: 5px;
  text-shadow: none;
}

button.accordion.active:after {
  content: "–";
}


/* this will adjst the max-height for active items*/

.accordion.active+.panel {
  max-height: inherit;
}


/* Style the accordion panel. Note: hidden by default */

div.panel {
  padding: 0;
  background-color: #f5f5f5;
  border: none;
  border-radius: 0px;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
}

div.panel li {
  list-style: none;
  border-top: solid 1px #ddd;
}

div.panel li:hover {
  background: #e0e0e0;
}

div.panel a {
  color: #1d1d1d;
  font-size: 15px;
  display: block;
  padding: 12px 0;
}

div.panel i.fa-angle-right {
  padding: 0 15px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="accordion">Section 1</button>
<div class="panel">
  <ul>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 1</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 2</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 3</a></li>
  </ul>
</div>

<button class="accordion">Section 2</button>
<div class="panel">
  <ul>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 1</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 2</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 3</a></li>
  </ul>
</div>

<button class="accordion">Section 3</button>
<div class="panel">
  <ul>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 1</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 2</a></li>
    <li><a href="#"><i class="fa fa-angle-right"></i>Link 3</a></li>
  </ul>
</div>
<hr/>
<div> <code>.accordion.active + .panel {
    max-height:inherit;
}</code></div>

Upvotes: 0

clabe45
clabe45

Reputation: 2454

Think about storing the index of the current open tab in a number variable. Then, remove the "active" class of acc[index] when any tab is clicked on.

Of course, you should store the index after you deactivate acc[index] so you won't deactivate the item being clicked.

Upvotes: 0

Related Questions