skip to Main Content

Webpage

I have a list to the right of the webpage, with 4 buttons.
When a button is clicked, its relevant content is displayed; this is achieved through JavaScript. An EventListener runs a function to toggle the class "active".

The button HTML element also has an onclick = myFunciton() that links to JS to hide the right arrow icon.

I want to make it so that only one of these content sections can be open at a time. How can I achieve this?

Here is my HTML code:

  <div class="container-fluid">
    <div class="sec2">
      <h1>A 44-letter alphabet.</h1>
      <h1>A phonetically consistent language.</h1>
      <h1>A determined teacher you can count on.</h1>
    </div>
    <div class="sec3">
      <ul class="sec2drop">
        <li>
          <button onclick="myFunction()" class="collapsible" id="colly1">
            Prepare for a language exam
            <i class="fa fa-caret-right" id="arrow0"></i>
          </button>
          <div class="content">
            <p>
              A hundred different reasons, one perfect outcome. Maybe you
              were born to Hungarian parents abroad, and decided to take a
              Hungarian language exam to replace one of your high school
              leaving exams.
            </p>
            <p>
              Maybe you're going to be an exchange student in Hungary or
              work there for some time. I'm happy to prepare you in video
              call sessions, both with verbal and written training.
            </p>
          </div>
        </li>
        <li>
          <button onclick="myFunction()" class="collapsible" id="colly2">
            Hungarian for kids
            <i class="fa fa-caret-right" id="arrow1"></i>
          </button>
          <div class="content">
            <p>
              Many Hungarians living abroad would like to teach their
              linguistics or national heritage. I will tailor online
              sessions for your child that suites their and your needs the
              best.
            </p>
            <p>
              You decide if you would like to supervise or participate in
              the lesson. Generally, children under 8 require parental or
              older sibling presence.
            </p>
          </div>
        </li>
        <li>
          <button onclick="myFunction()" class="collapsible" id="colly3">
            Take on a challenge
            <i class="fa fa-caret-right" id="arrow2"></i>
          </button>
          <div class="content">
            <p>
              Whether you spontaneously decided to learn one of the hardest
              languages in the world, or you want to reconnect with your
              Hungarian heritage, I will guide you along the way. Are you a
              newbie or an advanced learner? Would you like specific types
              of homework in between lessons? I will adapt to your needs.
            </p>
          </div>
        </li>
        <li>
          <button onclick="myFunction()" class="collapsible" id="colly4">
            Translation services
            <i class="fa fa-caret-right" id="arrow3"></i>
          </button>
          <div class="content">
            <p>
              English to Hungarian or Hungarian to English. You can book my
              written translation services and choose the package most
              suitable to you.
            </p>
          </div>
        </li>
      </ul>
    </div>
  </div>

Here is my CSS code:

/* Style the button that is used to open and close the collapsible content */
.collapsible {
  background-color: transparent;
  cursor: pointer;
  padding: 18px;
  margin-left: 10px;
  border: none;
  font-size: 15px;
  width: 100%;
  display: flex;
  justify-content: space-between;
}

/* Style the collapsible content. Note: hidden by default */
.content {
  padding: 0px 18px;
  display: none;
  overflow: hidden;
  background-color: wheat;
}

Here is my JavaScript code:

var coll = document.getElementsByClassName("collapsible");
var i;

for (i = 0; i < coll.length; i++) {
  coll[i].addEventListener("click", function () {
    this.classList.toggle("active");
    var content = this.nextElementSibling;
    if (content.style.display === "block") {
      content.style.display = "none";
    } else {
      content.style.display = "block";
    }
  });
}

function myFunction() {
  for (y = 0; y < 4; y++) {
    var x = document.getElementById(`arrow${y}`);
    if (x.style.display === "none") {
      x.style.display = "block";
    } else {
      x.style.display = "none";
    }
  }
}

3

Answers


  1. You can achieve this just to collapse all active elements. Check the collapseAll() function.

    var coll = document.getElementsByClassName("collapsible");
    var i;
    
    for (i = 0; i < coll.length; i++) {
      coll[i].addEventListener("click", function() {
    
        collapseAll()
    
        this.classList.toggle("active");
        var content = this.nextElementSibling;
        if (content.style.display === "block") {
          content.style.display = "none";
        } else {
          content.style.display = "block";
        }
      });
    }
    
    function collapseAll() {
      var activeElements = document.querySelectorAll(".collapsible.active")
      for (j = 0; j < activeElements.length; j++) {
        activeElements[j].classList.toggle("active")
        activeElements[j].nextElementSibling.style.display = "none";
      }
    }
    
    function myFunction() {
      for (y = 0; y < 4; y++) {
        var x = document.getElementById(`arrow${y}`);
        if (x.style.display === "none") {
          x.style.display = "block";
        } else {
          x.style.display = "none";
        }
      }
    }
    .collapsible {
      background-color: transparent;
      cursor: pointer;
      padding: 18px;
      margin-left: 10px;
      border: none;
      font-size: 15px;
      width: 100%;
      display: flex;
      justify-content: space-between;
    }
    
    
    /* Style the collapsible content. Note: hidden by default */
    
    .content {
      padding: 0px 18px;
      display: none;
      overflow: hidden;
      background-color: wheat;
    }
    <div class="container-fluid">
      <div class="sec2">
        <h1>A 44-letter alphabet.</h1>
        <h1>A phonetically consistent language.</h1>
        <h1>A determined teacher you can count on.</h1>
      </div>
      <div class="sec3">
        <ul class="sec2drop">
          <li>
            <button onclick="myFunction()" class="collapsible" id="colly1">
              Prepare for a language exam
              <i class="fa fa-caret-right" id="arrow0"></i>
            </button>
            <div class="content">
              <p>
                A hundred different reasons, one perfect outcome. Maybe you were born to Hungarian parents abroad, and decided to take a Hungarian language exam to replace one of your high school leaving exams.
              </p>
              <p>
                Maybe you're going to be an exchange student in Hungary or work there for some time. I'm happy to prepare you in video call sessions, both with verbal and written training.
              </p>
            </div>
          </li>
          <li>
            <button onclick="myFunction()" class="collapsible" id="colly2">
              Hungarian for kids
              <i class="fa fa-caret-right" id="arrow1"></i>
            </button>
            <div class="content">
              <p>
                Many Hungarians living abroad would like to teach their linguistics or national heritage. I will tailor online sessions for your child that suites their and your needs the best.
              </p>
              <p>
                You decide if you would like to supervise or participate in the lesson. Generally, children under 8 require parental or older sibling presence.
              </p>
            </div>
          </li>
          <li>
            <button onclick="myFunction()" class="collapsible" id="colly3">
              Take on a challenge
              <i class="fa fa-caret-right" id="arrow2"></i>
            </button>
            <div class="content">
              <p>
                Whether you spontaneously decided to learn one of the hardest languages in the world, or you want to reconnect with your Hungarian heritage, I will guide you along the way. Are you a newbie or an advanced learner? Would you like specific types of homework
                in between lessons? I will adapt to your needs.
              </p>
            </div>
          </li>
          <li>
            <button onclick="myFunction()" class="collapsible" id="colly4">
              Translation services
              <i class="fa fa-caret-right" id="arrow3"></i>
            </button>
            <div class="content">
              <p>
                English to Hungarian or Hungarian to English. You can book my written translation services and choose the package most suitable to you.
              </p>
            </div>
          </li>
        </ul>
      </div>
    </div>
    Login or Signup to reply.
  2. It may not be the best idea to use inline event listeners. Here is a minimal example, using event delegation, data-attributes to identify what needs to unfold, and a css class to activate the element to unfold.

    document.addEventListener(`click`, handle);
    
    function handle(evt) {
      if (evt.target.dataset.unfold) {
        // hide currently activated (if applicable)
        document.querySelector(`.collapsible.active`)
          ?.classList.remove(`active`);
        // activate from button data attribute
        return document.querySelector(`#${evt.target.dataset.unfold}`)
          .classList.add(`active`);
      }
    }
    .collapsible {
      display: none;
    }
    
    .collapsible.active {
      display: block;
    }
    <button data-unfold="firstDiv">First</button>
    <button data-unfold="secondDiv">Second</button>
    
    <div id="firstDiv" class="collapsible">The first div</div>
    <div id="secondDiv" class="collapsible">The second div</div>
    Login or Signup to reply.
  3. Your website is perfectly suited for use of the The Details disclosure element.

    The <details><summary> element already incorporates an ‘open’/’close’ mechanism, therefore there is no need to create that with Javascript:

    • When a user clicks the <summary> element of a closed <details> element the mechanism adds the boolean attribute open to the <details> element and shows the content below the <summary>. Upon successive click that attribute gets removed and the details closed again, hiding the content.
    • Disclosed details (.content) stay open until the user closes them again.

    As you want only one .content item open at a time, simple Javascript functionality is required to close an already opened <details> before opening the next upon user click.

    In the snippet I changed the content of .sec3 to work with <details><summary> and added the forementioned simple Javascript to toggle .content visibility.
    I removed your FontAwesome icons and made summary of "Prepare for a language exam" work with FontAwesome while the other three details use the HTML default carets. This way you can see the difference and choose which to keep. "Prepare for a language exam" also showcases how to nest <details><summary> if so required.

    The snippet is commented and should be self-explanatory:

    var currentDetail; // reference to current [open] details
    
    // Attach a listener to each .main-detail <summary>
    // Beware: nested details stay [open] in the back even if main details is closed
    
    document.querySelectorAll('.main-detail>summary').forEach(el => {
    
        // This event triggers before <details> 'toggle' event
        el.addEventListener("click", event => {
    
            // Get reference to closest parent .main-detail
            const closest = event.currentTarget.closest('.main-detail');
    
            // Remember:
            // the HTML mechanism automatically adds the [open] atttribute
            // upon user click, we don't have to do it ourselves...
    
            if (closest.open) { // About to trigger 'toggle'...
                currentDetail = null; // all main details closed
            }
    
            else { // Not null and different main details
                if ((currentDetail) && (currentDetail != closest)) {
                    // close current open main details first
                    currentDetail.removeAttribute('open');
                 };
                 // Save newly opened main details
                 currentDetail = closest;
            }
            // ...NOW the toggle takes place
        });
    });
    details .content {
      padding: 0 1rem;
      overflow: hidden;
      background-color: wheat;
    }
    
    /******************/
    /* Some eye-candy */
    /******************/
    .main-detail[open] {
        border-top   : 1px solid Gray;
        border-bottom: 1px solid Gray;
        margin: 0.5rem 0;
    }
    .main-detail[open]>summary   { padding: 0.5em 0; font-weight: bold }
    
    .main-detail details         { font-style: italic } /* nested details */
    details details:last-of-type { padding-bottom: 0.5rem }
    
    /* [OPTIONAL] Custom FontAwesome 6 carets replacing default carets */
    /*
        If you want to use Fontawesome for all carets,
        change all '#colly1' below to 'summary',
        otherwise remove below four rules entirely...
    */
    #colly1        { display: flex; justify-content: space-between }
    #colly1::after {
        font-family : "Font Awesome 6 Free";
        font-weight : 900;
        font-style  : normal;
        font-variant: normal;
        line-height : 1;
        text-rendering: auto;
        padding-left: 0.5rem;
    }
    details       > #colly1::after { content: "f0da" } /* Caret right */
    details[open] > #colly1::after { content: "f0d7" } /* Caret down  */
    /* end Fontawesome */
    
    /*************/
    /* Just demo */
    /*************/
     /* * { outline: 1px dashed } /* for debugging */
    
    *    { box-sizing: border-box }
    
    body {
        margin: 0; padding: 1rem;
        background-image: url('https://picsum.photos/id/100/1920/1200');
        background-attachement: fixed;
        background-repeat: no-repeat;
    
        cursor: default;
    }
    summary { cursor: pointer } /* odd, this should be default */
    
    /* Responsive behavior */
    .container-fluid {
        display: flex; flex-flow: row wrap;
        gap: 2rem;
    }
    /* all sections */
    .container-fluid > * {
        flex: 1; /* grow to fill assigned space */
        /* at least 20rem, but 100% when less available */
        min-width: min(20rem,100%);
    }
    
    .sec2 { flex: 8 } /* [OPTIONAL] space distribution */
    .sec3 { flex: 2 }
    
    .sec2 h1 { word-break: break-word; hyphens: auto }
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css" rel="stylesheet"/>
    
    <div class="container-fluid">
        <div class="sec2">
            <h1>A 44-letter alphabet.</h1>
            <h1>A phonetically consistent language.</h1>
            <h1>A determined teacher you can count on.</h1>
        </div>
    
        <div class="sec3">
            <details class="main-detail">
                <summary id="colly1">Prepare for a language exam</summary>
                <div class="content">
                    <p>
                        A hundred different reasons, one perfect outcome. Maybe you
                        were born to Hungarian parents abroad, and decided to take a
                        Hungarian language exam to replace one of your high school
                        leaving exams.
                    </p>
                    <p>
                        Maybe you're going to be an exchange student in Hungary or
                        work there for some time. I'm happy to prepare you in video
                        call sessions, both with verbal and written training.
                    </p>
                    <details>
                        <summary>nested details (not handled by JS)</summary>
                        <p>some nested collapsible info, stays [open], even when main details are closed...</p>
                        <ul>
                            <li>list item 1</li>
                            <li>list item 2</li>
                            <li>list item 3</li>
                        </ul>
                        <details>
                            <summary>even deeper nested details (dito)</summary>
                            <p>some nested collapsible info, stays [open], even when main details are closed...</p>
                            <ul>
                                <li>list item 4</li>
                                <li>list item 5</li>
                                <li>list item 6</li>
                            </ul>
                        </details>
                    </details>
                </div>
            </details>
    
            <details class="main-detail">
                <summary id="colly2">Hungarian for kids</summary>
                <div class="content">
                    <p>
                        Many Hungarians living abroad would like to teach their
                        linguistics or national heritage. I will tailor online
                        sessions for your child that suites their and your needs the
                        best.
                    </p>
                    <p>
                        You decide if you would like to supervise or participate in
                        the lesson. Generally, children under 8 require parental or
                        older sibling presence.
                    </p>
                </div>
            </details>
    
            <details class="main-detail">
                <summary id="colly3">Take on a challenge</summary>
                <div class="content">
                    <p>
                        Whether you spontaneously decided to learn one of the hardest
                        languages in the world, or you want to reconnect with your
                        Hungarian heritage, I will guide you along the way. Are you a
                        newbie or an advanced learner? Would you like specific types
                        of homework in between lessons? I will adapt to your needs.
                    </p>
                </div>
            </details>
    
            <details class="main-detail">
                <summary id="colly4"> Translation services</summary>
                <div class="content">
                    <p>
                        English to Hungarian or Hungarian to English. You can book my
                        written translation services and choose the package most
                        suitable to you.
                    </p>
                </div>
            </details>
        </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search