skip to Main Content

I have a small accordion code. When I click on the icon in the code, the accordion opens. However, I want it to open when I click on the title.

In other words, I want the accordion to open both when I click on the title and when I click on the icon.

How can I do this, can you help me?

function toggleAccordion(t) {
  const content = t.nextElementSibling;
  const arrow = t.querySelector('.arrow');

  if (content.classList.contains('hidden')) {
    content.classList.remove('hidden');
    content.classList.add('visible');
    arrow.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708"/></svg>';
  } else {
    content.classList.remove('visible');
    content.classList.add('hidden');
    arrow.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill-rule="evenodd" d="M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708z"/> </svg>';
  }
}

document.querySelectorAll('.title-label').forEach(label => {
  label.addEventListener('click', function() {
    toggleAccordion(this.closest('.title'));
  });
});
.arrow {
  font-size: 18px;
}

.hidden {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.5s ease-out;
}

.visible {
  max-height: 1200px;
  overflow: hidden;
  transition: max-height 0.5s ease-in;
}

input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  width: 20px;
  height: 20px;
  border: 2px solid #055274;
  border-radius: 50%;
  outline: none;
  cursor: pointer;
  position: relative;
  vertical-align: middle;
}

input[type="checkbox"]:checked::before {
  content: "";
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-color: #055274;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

label {
  display: inline-flex;
  align-items: center;
  font-size: 14px;
  font-weight: 600;
  font-family: Manrope, sans-serif;
  color: #055274;
  gap: 8px;
  cursor: pointer;
  margin: 2px;
}

label span {
  margin-left: 8px;
  vertical-align: middle;
}

.checkboxer {
  font-size: 12px;
}

a {
  text-decoration: none;
  color: #055274;
}

.title-label {
  cursor: pointer;
}

.title-checkbox {
  display: inline-flex;
  align-items: center;
  font-size: 16px;
  font-weight: 600;
  font-family: Manrope, sans-serif;
  color: #055274;
  gap: 8px;
}

.containerr {
  margin-bottom: 8px;
}
<div class="containerr">
  <div class="title" onclick="toggleAccordion(this)">
    <label class="title-label"><input type="checkbox" class="title-checkbox" name="plastic_surgery" value="Liposuction"> Weight Loss Treatments</label>
    <span id="accordionArrow" class="arrow">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-down" viewBox="0 0 16 16">
                    <path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708"/>
                </svg>
            </span>
  </div>
  <div id="accordionContent" class="hidden">
    <label><input type="checkbox" class="checkboxer" name="plastic_surgery" value="Liposuction"><a href="/gastric-sleeve/" target="_blank"> Gastric Sleeve</a></label><br>
    <label><input type="checkbox" class="checkboxer" name="plastic_surgery"><a href="/gastric-balloon/" target="_blank"> Gastric Balloon</a></label><br>
    <label><input type="checkbox" class="checkboxer" name="plastic_surgery"><a href="/stomach-gastric-botox/" target="_blank"> Stomach Gastric Botox</a></label><br>
  </div>
</div>

2

Answers


  1. Complicated because the click will trigger on all child elements. Normally stopPropagation should work, but here I use the working radio instead

    function toggleAccordion(t) {
      const content = t.nextElementSibling;
      const check = document.querySelector('.title-checkbox').checked;
      const arrow = t.querySelector('.arrow');
      content.classList.toggle('hidden',!check);
      content.classList.toggle('visible',check);
      const svg = check ?  '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill-rule="evenodd" d="M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708z"/> </svg>' : '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708"/></svg>'
      arrow.innerHTML = svg;
    }
    
    document.querySelector('.containerr').addEventListener('click', (e) => {
      e.stopPropagation()  
      const tgt = e.target.closest('.title');
      if (tgt) {
        toggleAccordion(tgt);
      }
    });
    .arrow {
      font-size: 18px;
    }
    
    .hidden {
      max-height: 0;
      overflow: hidden;
      transition: max-height 0.5s ease-out;
    }
    
    .visible {
      max-height: 1200px;
      overflow: hidden;
      transition: max-height 0.5s ease-in;
    }
    
    input[type="checkbox"] {
      appearance: none;
      -webkit-appearance: none;
      -moz-appearance: none;
      width: 20px;
      height: 20px;
      border: 2px solid #055274;
      border-radius: 50%;
      outline: none;
      cursor: pointer;
      position: relative;
      vertical-align: middle;
    }
    
    input[type="checkbox"]:checked::before {
      content: "";
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background-color: #055274;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
    
    label {
      display: inline-flex;
      align-items: center;
      font-size: 14px;
      font-weight: 600;
      font-family: Manrope, sans-serif;
      color: #055274;
      gap: 8px;
      cursor: pointer;
      margin: 2px;
    }
    
    label span {
      margin-left: 8px;
      vertical-align: middle;
    }
    
    .checkboxer {
      font-size: 12px;
    }
    
    a {
      text-decoration: none;
      color: #055274;
    }
    
    .title-label {
      cursor: pointer;
    }
    
    .title-checkbox {
      display: inline-flex;
      align-items: center;
      font-size: 16px;
      font-weight: 600;
      font-family: Manrope, sans-serif;
      color: #055274;
      gap: 8px;
    }
    
    .containerr {
      margin-bottom: 8px;
    }
    <div class="containerr">
      <div class="title">
        <label class="title-label"><input type="checkbox" class="title-checkbox" name="plastic_surgery" value="Liposuction"> Weight Loss Treatments
        <span id="accordionArrow" class="arrow">
          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-down" viewBox="0 0 16 16">
            <path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708"/>
          </svg>
        </span></label>
      </div>
      <div id="accordionContent" class="hidden" >
        <label><input type="checkbox" class="checkboxer" name="plastic_surgery" value="Liposuction"><a href="/gastric-sleeve/" target="_blank"> Gastric Sleeve</a></label><br>
        <label><input type="checkbox" class="checkboxer" name="plastic_surgery"><a href="/gastric-balloon/" target="_blank"> Gastric Balloon</a></label><br>
        <label><input type="checkbox" class="checkboxer" name="plastic_surgery"><a href="/stomach-gastric-botox/" target="_blank"> Stomach Gastric Botox</a></label><br>
      </div>
    </div>
    Login or Signup to reply.
  2. I changed the listeners so that the checkboxes are listening for a change and left the arrow for a click since it’s not in the tab index.
    With listening for change, the checkbox now is accessible via keyboard AND mouse click.
    Futhermore i changed the arrow in its initial state to the one that is used when the contents are hidden.

    I highly recommend the change of the content to a unordered list <ul>. You’ll do screenreader users and other accessibility tools a favor to mark lists as such in hindsight to the web content accessibility guidelines (WCAG).
    If you’re on it, add highlights for :focus on the elements to make them usable by keyboard.
    Furthermore you may consider using just "hidden" as class and visible as the default state. You only add or remove the hidden class and do not need to add visible again.

    function toggleAccordion(t) {
      const content = t.nextElementSibling;
      const arrow = t.querySelector('.arrow');
    
      if (content.classList.contains('hidden')) {
        content.classList.remove('hidden');
        content.classList.add('visible');
        arrow.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708"/></svg>';
      } else {
        content.classList.remove('visible');
        content.classList.add('hidden');
        arrow.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill-rule="evenodd" d="M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708z"/> </svg>';
      }
    }
    
    document.querySelectorAll('.title-label>.title-checkbox').forEach(label => {
        label.addEventListener('change', function() {
            toggleAccordion(this.closest('.title'));
        });
    });
    .arrow {
      font-size: 18px;
    }
    
    .hidden {
      max-height: 0;
      overflow: hidden;
      transition: max-height 0.5s ease-out;
    }
    
    .visible {
      max-height: 1200px;
      overflow: hidden;
      transition: max-height 0.5s ease-in;
    }
    
    input[type="checkbox"] {
      appearance: none;
      -webkit-appearance: none;
      -moz-appearance: none;
      width: 20px;
      height: 20px;
      border: 2px solid #055274;
      border-radius: 50%;
      outline: none;
      cursor: pointer;
      position: relative;
      vertical-align: middle;
    }
    
    input[type="checkbox"]:checked::before {
      content: "";
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background-color: #055274;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
    
    label {
      display: inline-flex;
      align-items: center;
      font-size: 14px;
      font-weight: 600;
      font-family: Manrope, sans-serif;
      color: #055274;
      gap: 8px;
      cursor: pointer;
      margin: 2px;
    }
    
    label span {
      margin-left: 8px;
      vertical-align: middle;
    }
    
    .checkboxer {
      font-size: 12px;
    }
    
    a {
      text-decoration: none;
      color: #055274;
    }
    
    .title-label {
      cursor: pointer;
    }
    
    .title-checkbox {
      display: inline-flex;
      align-items: center;
      font-size: 16px;
      font-weight: 600;
      font-family: Manrope, sans-serif;
      color: #055274;
      gap: 8px;
    }
    
    .containerr {
      margin-bottom: 8px;
    }
    <div class="containerr">
      <div class="title">
        <label class="title-label"><input type="checkbox" class="title-checkbox" name="plastic_surgery" value="Liposuction"> Weight Loss Treatments</label>
        <span id="accordionArrow" class="arrow"  onclick="toggleAccordion(this.closest('.title'))">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill-rule="evenodd" d="M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708z"/> </svg>
                </span>
      </div>
      <div id="accordionContent" class="hidden">
        <label><input type="checkbox" class="checkboxer" name="plastic_surgery" value="Liposuction"><a href="/gastric-sleeve/" target="_blank"> Gastric Sleeve</a></label><br>
        <label><input type="checkbox" class="checkboxer" name="plastic_surgery"><a href="/gastric-balloon/" target="_blank"> Gastric Balloon</a></label><br>
        <label><input type="checkbox" class="checkboxer" name="plastic_surgery"><a href="/stomach-gastric-botox/" target="_blank"> Stomach Gastric Botox</a></label><br>
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search