Search code examples
cssdropdown

Change FA Icon only with CSS


I have a sidebar in a project with Reactand I want that, when opening a menu item type Dropdown, the arrow changes position according to the state of the dropdown. (closed to the right, open to the bottom).

I implemented it with useState and it works without problems, depending on the statecurrent one dropdownI put one icon or another.

Question:

Can this behavior be simulated using only CSS? (I prefer to do it like this to learn on the one hand, and mainly because if I have a sidebar with 10 dropdowns or more, I will have many states and it is not the idea).

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
body {
  font-family: "Lato", sans-serif;
}

/* Fixed sidenav, full height */
.sidenav {
  height: 60%;
  width: 200px;
  position: fixed;
  z-index: 1;
  top: 0;
  left: 0;
  background-color: #111;
  overflow-x: hidden;
  padding-top: 20px;
}

/* Style the sidenav links and the dropdown button */
.sidenav a, .dropdown-btn {
  padding: 6px 8px 6px 16px;
  text-decoration: none;
  font-size: 20px;
  color: #818181;
  display: block;
  border: none;
  background: none;
  width: 100%;
  text-align: left;
  cursor: pointer;
  outline: none;
}

/* Dropdown container (hidden by default). Optional: add a lighter background color and some left padding to change the design of the dropdown content */
.dropdown-container {
  display: none;
  background-color: #262626;
  padding-left: 8px;
}


</style>
</head>
<body>

<div class="sidenav">
  <button class="dropdown-btn">Dropdown 
    <i class="fa fa-caret-down"></i>
  </button>
  <div class="dropdown-container">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
  </div>
</div>


<script>
/* Loop through all dropdown buttons to toggle between hiding and showing its dropdown content - This allows the user to have multiple dropdowns without any conflict */
var dropdown = document.getElementsByClassName("dropdown-btn");
var i;

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

</body>
</html> 

I wanna change instead caret-down for caret-right onClick in the dropdown button. And if i click again, right instead down.


Solution

  • Fontawesome works by styling a pseudo element of an i element.

    This means you can change a Fontawesome icon or you can just rotate the one that you have in CSS. For example, to have a right facing arrow instead of the down facing one next to the word Dropdown when the submenu is not dropped down and pointing down when it is, you could put this CSS in your style sheet:

    .sidenav button.dropdown-btn i.fa-caret-down::before {
            transform: rotate(-90deg);
            display: inline-block;
        }
    
    
    .sidenav button.active i.fa-caret-down::before {
        transform: rotate(0deg);
        display: inline-block;
    }
    

    Here's the snippet

    /* Loop through all dropdown buttons to toggle between hiding and showing its dropdown content - This allows the user to have multiple dropdowns without any conflict */
    var dropdown = document.getElementsByClassName("dropdown-btn");
    var i;
    
    for (i = 0; i < dropdown.length; i++) {
      dropdown[i].addEventListener("click", function() {
      this.classList.toggle("active");
      var dropdownContent = this.nextElementSibling;
      if (dropdownContent.style.display === "block") {
      dropdownContent.style.display = "none";
      } else {
      dropdownContent.style.display = "block";
      }
      });
    }
    body {
      font-family: "Lato", sans-serif;
    }
    
    /* Fixed sidenav, full height */
    .sidenav {
      height: 60%;
      width: 200px;
      position: fixed;
      z-index: 1;
      top: 0;
      left: 0;
      background-color: #111;
      overflow-x: hidden;
      padding-top: 20px;
    }
    
    /* Style the sidenav links and the dropdown button */
    .sidenav a, .dropdown-btn {
      padding: 6px 8px 6px 16px;
      text-decoration: none;
      font-size: 20px;
      color: #818181;
      display: block;
      border: none;
      background: none;
      width: 100%;
      text-align: left;
      cursor: pointer;
      outline: none;
    }
    
    /* Dropdown container (hidden by default). Optional: add a lighter background color and some left padding to change the design of the dropdown content */
    .dropdown-container {
      display: none;
      background-color: #262626;
      padding-left: 8px;
    }
    
    .sidenav button.dropdown-btn i.fa-caret-down::before {
            transform: rotate(-90deg);
            display: inline-block;
        }
    
    
    .sidenav button.active i.fa-caret-down::before {
        transform: rotate(0deg);
        display: inline-block;
    }
    <!DOCTYPE html>
    <html>
    <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
    
    
    <div class="sidenav">
      <button class="dropdown-btn">Dropdown 
        <i class="fa fa-caret-down"></i>
      </button>
      <div class="dropdown-container">
        <a href="#">Link 1</a>
        <a href="#">Link 2</a>
        <a href="#">Link 3</a>
      </div>
    </div>