Ale
Ale

Reputation: 137

how to change the icon of a div by clicking and using vanilla js?

I'm trying to click on a title to display content and change the icon next to the title.

The main idea is that there is a plus sign and that when clicking, the content is visible and the icon changes to a minus sign.

I am working with scss and vanilla js, so far I have this:

var jsaccordion = {
    init : function (target) {  
      var headers = document.querySelectorAll("#" + target + " .accordion-titulo");
      if (headers.length > 0) { for (var head of headers) {
        head.addEventListener("click", jsaccordion.select);
      }}
    },

    select : function () {        
      var contents = this.nextElementSibling;
      contents.classList.toggle("open");
    }
  };
  window.addEventListener('load', function(){
    jsaccordion.init("accordion-definiciones");
  });
.accordion-titulo::before {
  content: ".";
  display: block;
  background: url("./../Iconos/Icono\ some-icon");
  background-repeat: no-repeat;
  background-position: center;
  cursor: pointer;
  width: 35px;
  height: 35px;
  color: transparent;
  float: right;
}
.accordion-texto {
  display: none;
  color: #808080;
  padding: 15px;
}
.accordion-texto.open {
  display: block;
}
.accordion-titulo.open {
  background: url("./../Iconos/Icono\ some-different-icon.svg");
  background-repeat: no-repeat;
  background-position: 98% center;
}
<div id="accordion-definiciones">
    <div class="my-3">
      <h3 class="accordion-titulo ">¿Lorem ipsum?</h3>
         <div class="accordion-texto">
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, animi perferendis necessitatibus sint molestiae eius magni! Libero voluptas mollitia laudantium, ad nihil cum quibusdam rerum laboriosam quia ea facere temporibus.</p>
         </div>
     </div>
</div>
                          

I know it can be easier with Jquery but I want to do it with vanilla js

Upvotes: 2

Views: 739

Answers (4)

epascarello
epascarello

Reputation: 207501

You can actually do it with just HTML and CSS

.accordion input[type="checkbox"] {
  display: none
}

.accordion input[type="checkbox"] + h3 {
   cursor: pointer;
}

.accordion input[type="checkbox"] + .accordion-titulo label:after {
  content: "\27F0";
}

.accordion input[type="checkbox"]:checked + .accordion-titulo label:after {
  content: "\27F1";
}

.accordion input[type="checkbox"] + .accordion-titulo + .accordion-texto {
  max-height: 0;
  overflow: auto;
  transition: max-height .8s;
}

.accordion input[type="checkbox"]:checked + .accordion-titulo + .accordion-texto {
  height: auto;
  max-height: 200px;
  transition: max-height .8s;
}

.accordion-texto {
  background-color: #CCC;
}
<div id="accordion-definiciones">
  <div class="my-3 accordion">
    <input type="checkbox" id="ac1">
    <h3 class="accordion-titulo "><label for="ac1">¿Lorem ipsum?</label></h3>
    <div class="accordion-texto">
      <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, animi perferendis necessitatibus sint molestiae eius magni! Libero voluptas mollitia laudantium, ad nihil cum quibusdam rerum laboriosam quia ea facere temporibus.</p>
    </div>
  </div>
</div>

Upvotes: 1

Rickard Elim&#228;&#228;
Rickard Elim&#228;&#228;

Reputation: 7591

Here is a pure CSS solution, using a hidden checkbox and the sibling selector (~) to toggle the visibility of a neighbor div and the symbol of a before element. I also took the liberty of styling everything slightly differently.

If you want a behavior where you automatically close an already open section, when clicking on a headline, then use radio-buttons with the same name attribute.

.hidden {
  display: none;
}

.accordion-titulo > label {
  cursor: pointer;
}

.accordion-titulo > label::before {
  content: "+";
  display: inline-block;
  width: 1rem;
}

input[type="checkbox"]:checked ~ .accordion-titulo > label::before {
  content: "-";
}

.accordion-texto {
  display: none;
  color: #808080;
  padding-left: 1rem;
  padding-bottom: 1rem;
}

input[type="checkbox"]:checked ~ .accordion-texto {
  display: block;  
}
    <div class="my-3">
      <input id="part-1" class="hidden" type="checkbox">
      <h3 class="accordion-titulo "><label for="part-1">Part 1</label></h3>
      <div class="accordion-texto">
        <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, animi perferendis necessitatibus sint molestiae eius magni! Libero voluptas mollitia laudantium, ad nihil cum quibusdam rerum laboriosam quia ea facere temporibus.</p>
      </div>
    </div>

    <div class="my-3">
      <input id="part-2" class="hidden" type="checkbox">
      <h3 class="accordion-titulo "><label for="part-2">Part 2</label></h3>
      <div class="accordion-texto">
        <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, animi perferendis necessitatibus sint molestiae eius magni! Libero voluptas mollitia laudantium, ad nihil cum quibusdam rerum laboriosam quia ea facere temporibus.</p>
      </div>
     </div>

Upvotes: 0

mgarcia
mgarcia

Reputation: 6325

From your code, it seems that the icon some-different-icon should be placed in a :before selector, as the icon some-icon is being added in a :before.

Also, on the JavaScript side you are setting the class open to the next sibling element of the .accordion-titulo (which is the .accordion-texto). So, your styles for .accordion-titulo.open will never apply.

Instead, I would set the open class in the .accordion-titulo element and show the .accordion-texto with the CSS sibling selector +.

Wrapping all that, the code would look like:

var jsaccordion = {
    init : function (target) {  
      var headers = document.querySelectorAll("#" + target + " .accordion-titulo");
      if (headers.length > 0) { for (var head of headers) {
        head.addEventListener("click", jsaccordion.select);
      }}
    },

    select : function () {        
      this.classList.toggle("open");
    }
  };
  window.addEventListener('load', function(){
    jsaccordion.init("accordion-definiciones");
  });
.accordion-titulo::before {
  content: " ";
  display: block;
  background: url("./../Iconos/Icono\ some-icon");
  background-repeat: no-repeat;
  background-position: center;
  cursor: pointer;
  width: 35px;
  height: 35px;
  color: transparent;
  float: right;
}
.accordion-texto {
  display: none;
  color: #808080;
  padding: 15px;
}
.accordion-titulo.open + .accordion-texto{
  display: block;
}
.accordion-titulo.open::before {
  background: url("./../Iconos/Icono\ some-different-icon.svg");
  background-repeat: no-repeat;
  background-position: 98% center;
}
<div id="accordion-definiciones">
    <div class="my-3">
      <h3 class="accordion-titulo ">¿Lorem ipsum?</h3>
         <div class="accordion-texto">
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, animi perferendis necessitatibus sint molestiae eius magni! Libero voluptas mollitia laudantium, ad nihil cum quibusdam rerum laboriosam quia ea facere temporibus.</p>
         </div>
     </div>
</div>
                          

Upvotes: 0

Austin Adams
Austin Adams

Reputation: 231

Something like this can do what you want (there are plenty other, probably better, ways to do it, but this does what you described).

var jsaccordion = {
    init : function (target) {  
      var headers = document.querySelectorAll("#" + target + " .accordion-titulo");
      if (headers.length > 0) { for (var head of headers) {
        head.addEventListener("click", jsaccordion.select);
      }}
    },

    select : function () {        
      var contents = this.nextElementSibling;
      if (this.innerHTML.includes("+")) {
        this.innerHTML = this.innerHTML.replace("+", "-");
      } else {
        this.innerHTML = this.innerHTML.replace("-", "+");
      }
      contents.classList.toggle("open");
    }
  };
  window.addEventListener('load', function(){
    jsaccordion.init("accordion-definiciones");
  });
.accordion-titulo::before {
  content: ".";
  display: block;
  background: url("./../Iconos/Icono\ some-icon");
  background-repeat: no-repeat;
  background-position: center;
  cursor: pointer;
  width: 35px;
  height: 35px;
  color: transparent;
  float: right;
}
.accordion-texto {
  display: none;
  color: #808080;
  padding: 15px;
}
.accordion-texto.open {
  display: block;
}
.accordion-titulo.open {
  background: url("./../Iconos/Icono\ some-different-icon.svg");
  background-repeat: no-repeat;
  background-position: 98% center;
}
<div id="accordion-definiciones">
    <div class="my-3">
      <h3 class="accordion-titulo ">¿Lorem ipsum? +</h3>
         <div class="accordion-texto">
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, animi perferendis necessitatibus sint molestiae eius magni! Libero voluptas mollitia laudantium, ad nihil cum quibusdam rerum laboriosam quia ea facere temporibus.</p>
         </div>
     </div>
</div>
                          

Upvotes: 0

Related Questions