Tips for adding icons that change when a button dropdown is clicked :after and :before

When using the after and before selectors, I am attempting to change the dropdown icon depending on whether it is open or closed. However, I have not been successful so far. As someone who is relatively new to this, I would appreciate any help in achieving this result.

I'm not completely sure if this is the correct approach.

Edit: Thanks to AStombaugh's answer, I managed to make some progress but I'm unsure if I'm doing it correctly. Can anyone provide guidance on whether my implementation is right or wrong? Apologies for my lack of experience, I am trying to grasp all aspects of JavaScript.

New code snippet:

var dropdownBtn = document.querySelectorAll('.drop_btn');
iconDrop = null;
lastOpened = null; //Include this for toggling dropdown

dropdownBtn.forEach(btn => btn.addEventListener('click', function() {
  var dropCont = this.nextElementSibling;
  let icon = this.querySelector('.icon_item');
  icon.classList.toggle("visible");
  dropCont.classList.toggle("show");

  //Include this for toggling dropdown
  if (lastOpened && lastOpened !== dropCont)
    lastOpened.classList.remove("show");
  lastOpened = dropCont;

  if (iconDrop && iconDrop !== icon)
    iconDrop.classList.remove("visible");
  iconDrop = icon;
}));
.drop_btn {
  background: #e0e0e0;
  padding: 10px;
  margin: 5px 0px 0px 0px;
}

.icon_item:after {
  font-family: fontAwesome;
  content: '\f078';
  float: right;
}

.icon_item.visible:after {
  font-family: fontAwesome;
  content: '\f00d';
}

.drop_btn:hover {
  background: #000;
  color: #fff;
}

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

.drop_container.show {
  max-height: 300px;
  transition: max-height 0.3s ease-in;
}

.drop_container>.item {
  display: flex;
  flex-direction: column;
  margin-left: 10px;
  padding: 10px 0px 0px 0px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">

<div class="dropdown-menu">

  <div class="drop_btn">One<span class="icon_item"></span></div>
  <div class="drop_container">
    <a class="item" href="#">Contact Us</a>
    <a class="item" href="#">Visit Us</a>
  </div>

  <div class="drop_btn">Two<span class="icon_item"></span></div>
  <div class="drop_container">
    <a class="item" href="#">Contact Us</a>
    <a class="item" href="#">Visit Us</a>
  </div>

</div>

Original code snippet:

var dropdownBtn = document.querySelectorAll('.drop_btn');
lastOpened = null; //Include this for toggling dropdown

dropdownBtn.forEach(btn => btn.addEventListener('click', function() {
  var dropCont = this.nextElementSibling;
  dropCont.classList.toggle("show");
  
  //Include this for toggling dropdown
  if (lastOpened && lastOpened !== dropCont)
      lastOpened.classList.remove("show");
      lastOpened = dropCont;
}));
.drop_btn {
  background: #e0e0e0;
  padding: 10px;
  margin: 5px 0px 0px 0px;
}

.drop_btn:before {
  font-family: fontAwesome;
  content: '\f077';
  float: right;
}

.drop_btn:after {
  font-family: fontAwesome;
  content: '\f078';
  float: right;
 }

.drop_btn:hover {
  background: #000;
  color: #fff;
}

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

.drop_container.show {
  max-height: 300px;
  transition: max-height 0.3s ease-in;
}

.drop_container > .item {
  display: flex;
  flex-direction: column;
  margin-left: 10px;
  padding: 10px 0px 0px 0px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">

<div class="dropdown-menu">

<div class="drop_btn">One</div>
<div class="drop_container">
  <a class="item" href="#">Contact Us</a>
  <a class="item" href="#">Visit Us</a>
</div>

<div class="drop_btn">Two</div>
<div class="drop_container">
  <a class="item" href="#">Contact Us</a>
  <a class="item" href="#">Visit Us</a>
</div>

</div>

Answer №1

:before and :after are not functioning as expected in this scenario. https://developer.mozilla.org/en-US/docs/Web/CSS/::before

Nevertheless, you have the option to treat Fontawesome icons as classes and then toggle them similar to how you handle the menu. Check out: to locate the desired icon, copy the HTML tag, add the class to your CSS (everything within the <i> excluding the fa part), and manipulate them just like any other CSS element. Insert the actual HTML tag wherever you wish to display the icon.

var dropdownBtn = document.querySelectorAll('.drop_btn');
iconDrop = null;
lastOpened = null; //Include this for toggling dropdown

dropdownBtn.forEach(btn => btn.addEventListener('click', function() {
  var dropCont = this.nextElementSibling;
  let icon = this.querySelector('.fa-angle-up');
  icon.classList.toggle("down");
  dropCont.classList.toggle("show");

  //Include this for toggling dropdown
  if (lastOpened && lastOpened !== dropCont)
    lastOpened.classList.remove("show");
  lastOpened = dropCont;

  if (iconDrop && iconDrop !== icon)
    iconDrop.classList.remove("down");
  iconDrop = icon;
}));
.drop_btn {
  background: #e0e0e0;
  padding: 10px;
  margin: 5px 0px 0px 0px;
}

.fa-angle-up {
  display: inline-block;
  position: absolute;
  right: 2em;
  margin: 0;
  padding: 0;
  transform: rotateY(0);
  transform-origin: center;
  transition: 0.3s linear;
}

.fa-angle-up.down {
  display: inline-block;
  position: absolute;
  right: 2em;
  margin: 0;
  padding: 0;
  transform: rotateZ(-180deg);
  transform-origin: center;
  transition: 0.3s linear;
}

.drop_btn:hover {
  background: #000;
  color: #fff;
}

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

.drop_container.show {
  max-height: 300px;
  transition: max-height 0.3s ease-in;
}

.drop_container>.item {
  display: flex;
  flex-direction: column;
  margin-left: 10px;
  padding: 10px 0px 0px 0px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">

<div class="dropdown-menu">

  <div class="drop_btn">One<i class="fa fa-angle-up"></i></div>
  <div class="drop_container">
    <a class="item" href="#">Contact Us</a>
    <a class="item" href="#">Visit Us</a>
  </div>

  <div class="drop_btn">Two<i class="fa fa-angle-up"></i></div>
  <div class="drop_container">
    <a class="item" href="#">Contact Us</a>
    <a class="item" href="#">Visit Us</a>
  </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

The background is failing to update properly - Jquery/Javascript/CSS

Novice Alert: JavaScript challenge! Right now, I'm working on a complex website project, but for the sake of isolating my issue, I've simplified it down. View Codepen Example The main goal is to have 3 images (represented by colors) appear as ...

Using forEach in React to simultaneously set multiple properties and return destructured output within the setState function

The following is the initial code snippet: setRows((rows) => rows.map((row) => selected && row.node === selected.id ? { ...row, row.a: "", row.b: "", row.c: "" } ...

Achieving success with the "silent-scroll" technique

I've been struggling to implement the 'scroll-sneak' JavaScript code for quite some time now. This code is designed to prevent the page from jumping to the top when an anchor link is clicked, while still allowing the link to function as inte ...

Determine the central x and y coordinates of elements depending on the specified screen dimensions

Is it possible to determine the center position of an element at a specific screen size using jQuery? I am looking to calculate the center position of an element based on provided height and width dimensions. For instance, if I provide the screen size (1 ...

Customize the images displayed for individual checkboxes in a QTreeView

I have customized a QTreeView by subclassing it, and I now have two columns with checkboxes. My goal is to assign different images to each column - one for the first column and another for the second column. While I am aware that I can change the image usi ...

Unable to get the DIV to float within its parent div

I'm having an issue with 2 DIV elements (the ones labeled "Module" below) not behaving as expected! When I try to float them so they appear side by side, they end up jumping outside of the parent container and falling below it. I've tried to trou ...

Using SASS to add class selectors in a loop

Can I achieve the desired CSS using SASS? .menu IMG { padding-left: 10px; } .menu .submenu IMG { padding-left: 20px; } .menu .submenu .submenu IMG { padding-left: 30px; } I need to add ".submenu" in each loop of the selector and update the padding accord ...

Clicking will open the link in both a new tab and the current tab

I'm looking to enable ng click functionality to work in both new tabs and the current tab. The URL is dynamically generated based on a certain condition. Here is the HTML: <a ng-href="{{myPathVariable }} " ng-click=" GoToThemes()" class="shift-l ...

Ways to refresh the child scope in Angular using an array

When receiving an array of data from the server in AngularJS, I need to dynamically update the $scope. The initial value is : $scope.form = {}; I would like to update it dynamically as follows: $scope.form = {"firstname" : "Alex"}; Both 'firstnam ...

Unselecting an "all selected" checkbox

I need help with my checkbox functionality. Currently, I have a checkbox that selects all options when clicked, but if one option is deselected, the "Select All" option remains checked. Any guidance on how to address this issue would be greatly appreciated ...

Error message in Django: 'Unable to locate the route for 'guestlist' with the given arguments: ('',)'

Before anything else, I want to mention that I am aware this issue has been raised frequently, but unfortunately, no solution could be found in other discussions. An error is being encountered when attempting to load a particular page. The relevant secti ...

What could be the reason why the AngularJS form is set to read-only

Explaining the setup of my app in HTML: <div ng-app="md-app"> <div id="general"> <ng-include src="template1" ng-controller="GeneralCtrl"></ng-include> </div> </div> The JavaScript function to fetch a pe ...

"Discover the steps to seamlessly display office documents on a webpage, similar to the functionality of

I am working on a project that involves using Node.js for the backend and AngularJS for the frontend. I need to be able to open Office files (.doc, .ppt, etc.) directly on my webpage. These files are stored on an Amazon S3 server. I am looking to implemen ...

Turn off HTML display for Internet Explorer users

I am looking to implement code that will block certain pages for Internet Explorer users, making it accessible only for Google Chrome and Firefox users. Do you have any suggestions on how I can achieve this or if there are existing solutions available? I& ...

What advantages does var offer over let in JavaScript?

Since the introduction of the new keyword let for variable declaration in JavaScript ES6, I find it difficult to come up with valid reasons to continue using var. Personally, I have been using let exclusively and haven't encountered any drawbacks so f ...

Using JavaScript functions to submit a form

I have a Javascript function set up to handle form submission. This function collects data from various textboxes, sets the form action with this data, and then submits it. However, I am encountering an issue where the URL of the following page does not ...

The ng-submit function in AngularJS is causing some issues and not functioning properly

In my HTML view, I have an ng-template which contains a form. I am trying to submit form data using ng-submit, but when I click on the submit button, nothing happens. However, other data bindings are working fine with text fields in the form, using ng-mo ...

Navigator Access - Handlebars

I'm currently making changes to the Ghost blog in order to support multiple languages. To achieve this, I am creating a Handlebars helper: hbs.registerHelper("language", function () { var lang = (navigator.language) ? navigator.language : nav ...

Steps for Transferring a Const from One File to Another

I am facing an issue with passing the const clouds variable from one file to another. There seems to be something I am overlooking and I have been looking at this for too long - I really appreciate your help! Source: getAVWXData.js import axios from &ap ...

What's the best way to switch between pages in NextJS using radio buttons?

I'm currently developing a NextJS project and have implemented a side navigation bar for user interaction. To give users a clear visual indication, I decided to use a radio button group. The idea is that when a user selects one of the options, the cor ...