Tips for modifying the icon of a div with a click event using vanilla JavaScript

My goal is to create a functionality where clicking on a title will reveal content and change the icon next to the title.

The concept is to have a plus sign initially, and upon clicking, the content becomes visible and the icon changes to a minus sign.

Currently, I am working with SCSS and vanilla JavaScript, and here is what I have so far:

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>
                          

Even though it could be simpler with jQuery, I prefer to achieve this functionality using vanilla JavaScript.

Answer №1

Creating an accordion using only HTML and CSS is totally doable

.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>

Answer №2

After reviewing your code, it appears that the some-different-icon icon should be placed in a :before selector, similar to how the some-icon icon is being added in a :before.

Additionally, in the JavaScript portion, you are adding the class open to the next sibling element of .accordion-titulo (which is .accordion-texto). This means that your styles for .accordion-titulo.open will not be applied.

Instead, I would recommend adding the open class to the .accordion-titulo element and showing the .accordion-texto using the CSS sibling selector +.

To summarize, your updated code should look like 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 () {        
      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>
                          

Answer №3

If you're looking to achieve a specific functionality, the code below can help you out. While there are many other ways to achieve the same result, this code snippet does exactly 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>
                          

Answer №4

Check out this innovative CSS solution that utilizes a hidden checkbox and the sibling selector (~) to toggle the visibility of a neighboring div and change the symbol of a before element. I've also added some unique styling to make it stand out.

If you're looking for a feature where clicking on a headline automatically closes any open sections, consider using 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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Vue.js is displaying one less item

Recently I started working with Vuejs and encountered an unexpected issue in my application. The purpose of my app is to search for channels using the YouTube API and then display those channels in a list. However, when I try to render the list of subscri ...

Failing to include a valid string in the path will result in an

Within my node API, I have a function that updates the email address array for either a contact or a farm. The concept is the same, but the difference lies in where the array is located: in farms it's within Records.emails, and in Contacts it's s ...

AngularJS button click not redirecting properly with $location.path

When I click a button in my HTML file named `my.html`, I want to redirect the user to `about.html`. However, when I try using `$location.path("\about")` inside the controller, nothing happens and only my current page is displayed without loading `abou ...

triggering a button click event in HTML

Below is the creation of a div: <div class="area1"> </div> By using AJAX, I was able to alter the HTML for the aforementioned div with this call: $('#abutton').click(function(e) { e.preventDefault(); ...

Encountering issues while retrieving information from database through AJAX and PHP

Update: The initial section of this question has been resolved and is now updated with the working code. ~ I'm currently developing a JavaScript application, and I'm encountering challenges with making an AJAX call function properly. While I ha ...

The JavaScript counterpart to jQuery's click event handler

I'm trying to figure out how to achieve the same effect as this jQuery code. var divQuery = $('.html5gallery-thumbs-0').children(); divQuery.on('click', function () {...} I attempted it like this: var divQuery = document.g ...

Removing multiple data rows in JSP using AJAX by selecting check boxes

I have a requirement where I need to store a list of objects (each with a unique id) as a session parameter. These objects are then displayed in a table in a JSP using JSTL. <c:forEach var="list" items="${PlayerList}"> <tr> <td> ...

Is it possible for the await block to be located outside of the async function that contains it?

setInterval(() => { // perform certain actions }, 1000) const bar = async () => { const response = await api_request(); do_actions(); } await bar(); When the foo function is set to run, will it interfere with the execution of the setInterval ...

List of items:1. The first item is elevated in its position

Can anyone explain why the first li item is displaying higher than the rest when I assign an id or class to the div element? https://i.sstatic.net/9SMdT.png Take a look at the code snippet below: <div id="pickList"> <ul *ngFor="let channel ...

How can I retrieve the decimal x and y coordinates when the mouse is moved in Typescript Angular?

I am in the process of transitioning my user interface from Flash/Flex, where it stores values in decimal format. I need to access and reuse these values. Here is a demo showcasing my problem. Here is a snippet: import { Component, Input } from '@an ...

Inject a jQuery form submission using .html() into a div element

I am currently working on developing a basic forum where users can view listed topics and have the option to add new ones on-the-fly by clicking a link or image. How can I detect and handle the form submission event for the dynamically added form within an ...

Ways to verify an iCheck located on the following page

Here is the code snippet I am currently working with: $("#add-new-size-grp").click( function (event) { event.preventDefault(); $.ajax({ type: "get", url:"ajax-get-sizes.php", success: function(result){ $("#sizeg ...

Trigger animation when the scroll position reaches 0.52 in Next.js using framer-motion

I’m working on a landing page and I have a section where I’d like to create a simple opacity animation using framer-motion. The issue is that these animations typically trigger as soon as you land on the page, but I want them to be based on scroll pos ...

Change the content inside a div depending on the value of a button

I am currently exploring how to change the content of a div based on button values, utilizing angular2+. Below is my implementation in HTML and js export class TestComponent implements OnInit { title:string = "provas"; constructor() { } popula ...

Tips for positioning two fields side by side on a webpage with CSS

I currently have two datepickers aligned vertically and I'm looking to display them in a horizontal layout with some spacing between them. What changes do I need to make in order to present these two calendar pickers side by side on the same row? Cou ...

Executing an HTTP request with JavaScript to interact with Salesforce

Looking to connect Salesforce with Recosence, an external system. The scenario involves Recosense pushing data to Salesforce for storage. I have successfully created a post HTTP service and tested it in Postman, which generates an access token and records ...

Utilizing React Native to dynamically generate buttons through a loop

I am currently working on retrieving data from the Eventbrite API. The information I am hoping to extract is the event names, which will then be added to a list. Within the render function, I aim to dynamically create buttons based on the number of event ...

Choosing specific information in Typescript response

I am encountering an issue with my HTML where it displays undefined(undefined). I have checked the data in the debugger and I suspect that there may be an error in how I am using the select data. Here is a snippet of the code: <div *ngIf="publishIt ...

Encountered a problem when injecting the angularjs $location service

I'm having some trouble getting the $location service to work in this code snippet: <script type="text/javascript> var $injector = angular.injector(['ng', 'kinvey', 'app.constants']); $in ...

javascript if an error occurs, refresh the webpage

Currently, I am inquiring about the most effective method for managing JavaScript errors. Given that my application relies heavily on JavaScript, despite diligent testing efforts, encountering bugs is almost certain. I'm interested in knowing if ther ...