20

I am trying to make a navigation menu I did all the HTML and CSS when come to javascript I am struck in the middle I am able to add a class to the element, but I am not able to remove the class remaining elements. Please help me with this.
here is my code

<!DOCTYPE html>
    <html>
    <head>
        <title>Navigation class Toggling</title>

        <style type="text/css">
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        header {
            width: 100%;
            height: auto;
            max-width: 600px;
            margin: 0 auto;
        }
        nav {
            width: 100%;
            height: 40px;
            background-color: cornflowerblue;
        }
        ul {
            list-style-type: none;
        }
        li {
            display: inline-block;
        }
        a {
            text-decoration: none;
            padding: 8px 15px;
            display: block;
            text-transform: capitalize;
            background-color: darkgray;
            color: #fff;
        }
        a.active {
            background-color: cornflowerblue;
        }
        </style>
    </head>
    <body>
    <header>
        <nav>
            <ul onclick="myFunction(event)">
                <li><a href="#">home</a></li>
                <li><a href="#">about</a></li>
                <li><a href="#">service</a></li>
                <li><a href="#">profile</a></li>
                <li><a href="#">portfolio</a></li>
                <li><a href="#">contact</a></li>
            </ul>
        </nav>
    </header>
    <script type="text/javascript">
        function myFunction(e) {
            e.target.className = "active";
        }
    </script>
    </body>
    </html>

and here is my Codepen

vivekkupadhyay
  • 2,851
  • 1
  • 22
  • 35
Venu Madhav
  • 413
  • 1
  • 5
  • 14
  • Did you check answers to this question? http://stackoverflow.com/q/6787383 – Fma Aug 17 '16 at 07:10
  • 1
    Possible duplicate of [How do I toggle an element's class in pure JavaScript?](http://stackoverflow.com/questions/18880890/how-do-i-toggle-an-elements-class-in-pure-javascript) – vivekkupadhyay Aug 17 '16 at 07:10

9 Answers9

43

Use document.querySelectorAll to find the element which currently have the active class, then you can remove that class.

function myFunction(e) {
  var elems = document.querySelectorAll(".active");
  [].forEach.call(elems, function(el) {
    el.classList.remove("active");
  });
  e.target.className = "active";
}

JSFIDDLE

Instead of document.querySelectorAll you can also use document.querySelector

 function myFunction(e) {
  var elems = document.querySelector(".active");
  if(elems !==null){
   elems.classList.remove("active");
  }
 e.target.className = "active";
}

JSFIDDLE 2

Edit

Instead of iterating through the entire collection you can select the element which have a class active using document.queryselector. Also provide an id to the ul so that you can target the specific element

function myFunction(e) {
  if (document.querySelector('#navList a.active') !== null) {
    document.querySelector('#navList a.active').classList.remove('active');
  }
  e.target.className = "active";
}
<style type="text/css">* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

header {
  width: 100%;
  height: auto;
  max-width: 600px;
  margin: 0 auto;
}

nav {
  width: 100%;
  height: 40px;
  background-color: cornflowerblue;
}

ul {
  list-style-type: none;
}

li {
  display: inline-block;
}

a {
  text-decoration: none;
  padding: 8px 15px;
  display: block;
  text-transform: capitalize;
  background-color: darkgray;
  color: #fff;
}

a.active {
  background-color: cornflowerblue;
}
<title>Navigation class Toggling</title>

<header>
  <nav>
    <ul onclick="myFunction(event)" id='navList'>
      <li><a href="#">home</a></li>
      <li><a href="#">about</a></li>
      <li><a href="#">service</a></li>
      <li><a href="#">profile</a></li>
      <li><a href="#">portfolio</a></li>
      <li><a href="#">contact</a></li>
    </ul>
  </nav>
</header>
brk
  • 48,835
  • 10
  • 56
  • 78
  • Hello from 2020. I tried using your solutions and got them to work when there is a hashtag in the anchor href. But when I put an actual link inside to a page in the site, it doesn't work. Is there a way to add an active class based on url location? – Casey Jun 13 '20 at 14:15
10

You could use classList methods to add, remove, or toggle.

First remove class name from previous one:

// assuming there's only one with such class name
// otherwise you need querySelectorAll and a loop
document.querySelector('.active').classList.remove('active')

Then add it to the new element:

e.target.classList.add('active')
Leo
  • 13,428
  • 5
  • 43
  • 61
5

HTML

<div class="container">
 <nav>
  <ul class="nav">
    <li class="nav__item"><a class="nav__link active" href="#">Home</a></li>
    <li class="nav__item"><a class="nav__link" href="#">Item 1</a></li>
    <li class="nav__item"><a class="nav__link" href="#">Item 2</a></li>
    <li class="nav__item"><a class="nav__link" href="#">Item 3</a></li>
    <li class="nav__item"><a class="nav__link" href="#">Item 4</a></li>
    <li class="nav__item"><a class="nav__link" href="#">Item 5</a></li>
  </ul>
 </nav>
</div>

CSS

    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    *::before, *::after {
        box-sizing: border-box;
    }

    .container {
      width: 100%;
      max-width: 1024px;
      display: block;
      margin: 30px auto;
    }

    ul {
      list-style: none;
    }

    a {
      text-decoration: none;
    }

    .nav {
      display: flex;
      flex-direction: row;
      justify-content: space-around;
      align-items: center;
    }

    .nav__item {
      padding: 1rem;
    }

    .nav__link {
      display: block;
      padding: .3125rem 1.5rem;
      text-transform: uppercase;
    }

    .nav__link.active  {
      border: 1px solid #ff4b4c;
      color: #ff4b4c;
    }

JS

    document.addEventListener('DOMContentLoaded', function() {

      const selector = '.nav__link';
      const elems = Array.from(document.querySelectorAll(selector));
      const navigation = document.querySelector('nav');

      function makeActive(evt) {
        const target = evt.target;

         if (!target || !target.matches(selector)) {
           return;
         }

        elems.forEach(elem => elem.classList.remove('active'));
        evt.target.classList.add('active');
      };

      navigation.addEventListener('mousedown', makeActive);

    });

BTW: A great solution is here: https://gomakethings.com/getting-all-sibling-elements-when-a-link-or-button-is-clicked-with-vanilla-js/

Mary Pieroszkiewicz
  • 363
  • 1
  • 5
  • 11
  • the "elems.forEach(elem => elem.classList.remove('active')); evt.target.classList.add('active');" was exactly what I was looking for. thanks! – Aaron Krauss Sep 10 '21 at 20:59
2

You can use "pure" JavaScript Element.classList to add and remove a class from your DOM element.

add: Add specified class values. If these classes already exist in attribute of the element, then they are ignored.

remove: Remove specified class values.

Use Document.querySelectorAll()to returnsa elements within the document that match the specified group of CSS selectors.

More info at:

https://developer.mozilla.org/en/docs/Web/API/Element/classList

https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll

Regarding your code, you can mark as active your element when User click on it using the following code:

window.myFunction = function(event) {
  // reset all menu items
  document.querySelectorAll('ul li a.active').forEach(function(item) {
  item.classList.remove('active');
})
  // mark as active selected menu item
  event.target.classList.add("active");
};
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

header {
  width: 100%;
  height: auto;
  max-width: 600px;
  margin: 0 auto;
}

nav {
  width: 100%;
  height: 40px;
  background-color: cornflowerblue;
}

ul {
  list-style-type: none;
}

li {
  display: inline-block;
}

a {
  text-decoration: none;
  padding: 8px 15px;
  display: block;
  text-transform: capitalize;
  background-color: darkgray;
  color: #fff;
}

a.active {
  background-color: cornflowerblue;
}

.active {
  ackground-color: red;
}
<header>
  <nav>
    <ul onclick="window.myFunction(event)">
      <li><a href="#">home</a></li>
      <li><a href="#">about</a></li>
      <li><a href="#">service</a></li>
      <li><a href="#">profile</a></li>
      <li><a href="#">portfolio</a></li>
      <li><a href="#">contact</a></li>
    </ul>
  </nav>
</header>
GibboK
  • 71,848
  • 143
  • 435
  • 658
1

you can do like this in pure javascript

   function myFunction(e,ev) {
      for(var i=0;i<e.children.length;i++)
        {
         e.children[i].childNodes[0].className = "";
          
        }
        ev.target.className = "active"; 
         
        }
<!DOCTYPE html>
    <html>
    <head>
        <title>Navigation class Toggling</title>

        <style type="text/css">
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        header {
            width: 100%;
            height: auto;
            max-width: 600px;
            margin: 0 auto;
        }
        nav {
            width: 100%;
            height: 40px;
            background-color: cornflowerblue;
        }
        ul {
            list-style-type: none;
        }
        li {
            display: inline-block;
        }
        a {
            text-decoration: none;
            padding: 8px 15px;
            display: block;
            text-transform: capitalize;
            background-color: darkgray;
            color: #fff;
        }
        a.active {
            background-color: cornflowerblue;
        }
        </style>
    </head>
    <body>
    <header>
        <nav>
            <ul onclick="myFunction(this,event)">
                <li><a href="#">home</a></li>
                <li><a href="#">about</a></li>
                <li><a href="#">service</a></li>
                <li><a href="#">profile</a></li>
                <li><a href="#">portfolio</a></li>
                <li><a href="#">contact</a></li>
            </ul>
        </nav>
    </header>
    <script type="text/javascript">
     
    </script>
    </body>
    </html>
Dinesh Shah
  • 1,163
  • 1
  • 7
  • 13
  • 1
    IMO the problem of using `.className = "";` is that it will remove any css `class` applied to the DOM element, when instead using `classList.remove` we can remove selectively only a specific CSS class. – GibboK Aug 17 '16 at 07:30
1

I'd personally stick with the document.querySelector method. querySelector accepts a CSS like query, which we will use to find an active class on the page. If it exists (the if statement), remove it and apply the new class on the target.

Please be aware that using className = "" will result in all classes being removed. It would be more neat to use classList for everything.

function myFunction(e) {
    var el = document.querySelector('.active');
  
    // Check if the element exists to avoid a null syntax error on the removal
    if(el) {
      el.classList.remove('active');
    }
  
    e.target.classList.add('active');
}
roberrrt-s
  • 7,914
  • 2
  • 46
  • 57
0

Below should help.

//Remove all classes by ID
document.getElementById("elementIdHere").className = "";
//If you wish to keep some classes on the element, use below
document.getElementById("elementIdHere").className = "keepClass";
IronAces
  • 1,857
  • 1
  • 27
  • 36
0

JS

var targets = document.querySelectorAll('.some-class');

targets.onclick = function(evt) {
    evt.classList.toggle('{your-class}');
};

For better browser support:

targets.onclick = function(evt) {
    var el = evt.target;
    var classes = el.className.split(" ");
    var classIndex = classes.indexOf('{your-class}');

    if (classIndex >= 0) {
        classes.splice(1, classIndex);
    } else {
        classes.push('{your-clas}');
    }

    el.className = classes.join(" ");
});
jedrzejginter
  • 402
  • 3
  • 10
0

window.myFunction = function(event) {
  var elms = document.querySelectorAll('ul li a');
  // reset all you menu items
  for (var i = 0, len = elms.length; i < len; i++) {
    elms[i].classList.remove('active');
  }
  // mark as active clicked menu item
  event.target.classList.add("active");
};
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

header {
  width: 100%;
  height: auto;
  max-width: 600px;
  margin: 0 auto;
}

nav {
  width: 100%;
  height: 40px;
  background-color: cornflowerblue;
}

ul {
  list-style-type: none;
}

li {
  display: inline-block;
}

a {
  text-decoration: none;
  padding: 8px 15px;
  display: block;
  text-transform: capitalize;
  background-color: pink;
  color: #fff;
}

a.active {
  background-color: blue;
}

.active {
  ackground-color: red;
}
<header>
  <nav>
    <ul onclick="window.myFunction(event)">
      <li><a href="#">home</a></li>
      <li><a href="#">about</a></li>
      <li><a href="#">service</a></li>
      <li><a href="#">profile</a></li>
      <li><a href="#">portfolio</a></li>
      <li><a href="#">contact</a></li>
    </ul>
  </nav>
</header>
satwick
  • 135
  • 9