184

I'm looking for a way to convert this jQuery code (which is used in responsive menu section) to pure JavaScript.

If it's hard to implement it's OK to use other JavaScript frameworks.

$('.btn-navbar').click(function()
{
    $('.container-fluid:first').toggleClass('menu-hidden');
    $('#menu').toggleClass('hidden-phone');

    if (typeof masonryGallery != 'undefined') 
        masonryGallery();
});
5
  • 1
    stackoverflow.com/questions/195951/… Commented Sep 18, 2013 at 19:46
  • 16
    document.getElementById("menu").classList.toggle("hidden-phone") :-) Commented Sep 18, 2013 at 19:59
  • classList isn't supported by some browsers: caniuse.com/classlist Commented Feb 27, 2014 at 13:42
  • 7
    Hey @max, want to pick an answer already? Commented Jan 29, 2016 at 15:32
  • 2
    Narrator: Max didn't pick an answer for the next seven years and, unbeknownst to Mike, shortly after writing this he would get divorced. Commented Feb 18, 2023 at 0:16

13 Answers 13

295

2014 answer: classList.toggle() is the standard and supported by most browsers.

Older browsers can use use classlist.js for classList.toggle():

var menu = document.querySelector('.menu') // Using a class instead, see note below.
menu.classList.toggle('hidden-phone');

As an aside, you shouldn't be using IDs (they leak globals into the JS window object).

Sign up to request clarification or add additional context in comments.

6 Comments

if we can't use IDs, then how ca we do that?
but, then we will have the same classes quantity instead old IDs, and use something like var myList = document.getElementsByClassName("abc") ?
@goku classes don't appear underneath the window object. Only IDs do. See 2ality.com/2012/08/ids-are-global.html
Supported by IE10 and IE11 except for the second parameter
Thank you so much! It's working now :) I add more option for loop: var All = document.querySelectorAll('.menu'); for (var i = 0; i < All.length; i++){ All[i].classList.toggle('hidden-phone'); }
|
28

Here is solution implemented with ES6

const toggleClass = (el, className) => el.classList.toggle(className);

usage example

toggleClass(document.querySelector('div.active'), 'active'); // The div container will not have the 'active' class anymore

3 Comments

ES6 is great, but this solution is simply using 'document.querySelector' and 'element.classList.toggle' per the other existing answers.
No solution is valid if it is "vendor oriented", Internet is open-standard-oriented.
this is not a solution for a multitude of files. does not work with querySelectorAll (at least in FF) so for those looking to toggle classes on multiple elements read on :-) (I did not read on at first - thus my comment! )
10

Take a look at this example: JS Fiddle

function toggleClass(element, className){
    if (!element || !className){
        return;
    }

    var classString = element.className, nameIndex = classString.indexOf(className);
    if (nameIndex == -1) {
        classString += ' ' + className;
    }
    else {
        classString = classString.substr(0, nameIndex) + classString.substr(nameIndex+className.length);
    }
    element.className = classString;
}

1 Comment

What if I had a class after "red" named "redOther"?
7

don't need regex just use classlist

var id=document.getElementById('myButton');


function toggle(el,classname){
if(el.classList.contains(classname)){
el.classList.remove(classname)
}
else{
el.classList.add(classname)
}
}




id.addEventListener('click',(e)=>{

toggle(e.target,'red')
})
.red{

background:red

}
<button id="myButton">Switch</button>

Simple Usage above Example

var id=document.getElementById('myButton');


function toggle(el,classname){
el.classList.toggle(classname)
}




id.addEventListener('click',(e)=>{

toggle(e.target,'red')
})
.red{

background:red

}
<button id="myButton">Switch</button>

Comments

4

This one works in earlier versions of IE also.

function toogleClass(ele, class1) {
  var classes = ele.className;
  var regex = new RegExp('\\b' + class1 + '\\b');
  var hasOne = classes.match(regex);
  class1 = class1.replace(/\s+/g, '');
  if (hasOne)
    ele.className = classes.replace(regex, '');
  else
    ele.className = classes + class1;
}
.red {
  background-color: red
}
div {
  width: 100px;
  height: 100px;
  margin-bottom: 10px;
  border: 1px solid black;
}
<div class="does red redAnother " onclick="toogleClass(this, 'red')"></div>

<div class="does collapse navbar-collapse " onclick="toogleClass(this, 'red')"></div>

1 Comment

\b word boundary is not consistent with css class name seperators. for example it doesn't work if class name contain dash ("-") char: btn, btn-red will both match'\\b' + 'btn' + '\\b' !!
4

If anyone looking to toggle class on mousehover/mousleave using Javascript here is the code for it

function changeColor() {
    this.classList.toggle('red');
    this.classList.toggle('green');
}

 document.querySelector('#btn').addEventListener('mouseenter', changeColor);
 document.querySelector('#btn').addEventListener('mouseleave', changeColor );

Demo Fiddle link: https://jsfiddle.net/eg2k7mLj/1/

Source: Toggle Class (Javascript based, without jQuery)

Comments

3

This is perhaps more succinct:

function toggle(element, klass) {
  var classes = element.className.match(/\S+/g) || [],
      index = classes.indexOf(klass);

  index >= 0 ? classes.splice(index, 1) : classes.push(klass);
  element.className = classes.join(' ');
}

Comments

1

Just for legacy reasons:

function toggleClassName(elementClassName, className) {
    const originalClassNames = elementClassName.split(/\s+/);
    const newClassNames = [];
    let found = false;
    for (let index = 0; index < originalClassNames.length; index++) {
        if (originalClassNames[index] === '') {
            continue;
        }
        if (originalClassNames[index] === className) {
            found = true;
            continue;
        }
        newClassNames.push(originalClassNames[index]);
    }
    if (!found) {
        newClassNames.push(className);
    }

    return newClassNames.join(' ');
}

console.assert(toggleClassName('', 'foo')                        === 'foo');
console.assert(toggleClassName('foo', 'bar')                     === 'foo bar');
console.assert(toggleClassName('foo bar', 'bar')                 === 'foo');
console.assert(toggleClassName('bar foo', 'bar')                 === 'foo');
console.assert(toggleClassName('foo bar baz', 'bar')             === 'foo baz');
console.assert(toggleClassName('foo-bar', 'foo')                 === 'foo-bar foo');
console.assert(toggleClassName('bar foo-bar', 'bar')             === 'foo-bar');
console.assert(toggleClassName('bar bar bar foo-bar bar', 'bar') === 'foo-bar');
console.assert(toggleClassName(" \n\nbar-bar \nbar-baz foo", 'bar-baz') === 'bar-bar foo');

element.className = toggleClassName(element.className, 'foo');

1 Comment

Won't be necessary probably. But I like that this also cleans up the list of class names by removing multiple occurrences of the same class.
0

Try this (hopefully it will work):

// mixin (functionality) for toggle class 
function hasClass(ele, clsName) {
    var el = ele.className;
    el = el.split(' ');
    if(el.indexOf(clsName) > -1){
        var cIndex = el.indexOf(clsName);
        el.splice(cIndex, 1);
        ele.className = " ";
        el.forEach(function(item, index){
          ele.className += " " + item;
        })
    }
    else {
        el.push(clsName);
        ele.className = " ";
        el.forEach(function(item, index){
          ele.className += " " + item;
        })
    }
}

// get all DOM element that we need for interactivity.

var btnNavbar =  document.getElementsByClassName('btn-navbar')[0];
var containerFluid =  document.querySelector('.container-fluid:first');
var menu = document.getElementById('menu');

// on button click job
btnNavbar.addEventListener('click', function(){
    hasClass(containerFluid, 'menu-hidden');
    hasClass(menu, 'hidden-phone');
})`enter code here`

Comments

0

Here is a code for IE >= 9 by using split(" ") on the className :

function toggleClass(element, className) {
    var arrayClass = element.className.split(" ");
    var index = arrayClass.indexOf(className);

    if (index === -1) {
        if (element.className !== "") {
            element.className += ' '
        }
        element.className += className;
    } else {
        arrayClass.splice(index, 1);
        element.className = "";
        for (var i = 0; i < arrayClass.length; i++) {
            element.className += arrayClass[i];
            if (i < arrayClass.length - 1) {
                element.className += " ";
            }
        }
    }
}

Comments

0

If you want to toggle a class to an element using native solution, you could try this suggestion. I have tasted it in different cases, with or without other classes onto the element, and I think it works pretty much:

(function(objSelector, objClass){
   document.querySelectorAll(objSelector).forEach(function(o){
      o.addEventListener('click', function(e){
        var $this = e.target,
            klass = $this.className,
            findClass = new RegExp('\\b\\s*' + objClass + '\\S*\\s?', 'g');

        if( !findClass.test( $this.className ) )
            if( klass ) 
                $this.className = klass + ' ' + objClass;
            else 
                $this.setAttribute('class', objClass);
        else 
        {
            klass = klass.replace( findClass, '' );
            if(klass) $this.className = klass;
            else $this.removeAttribute('class');
        }
    });
  });
})('.yourElemetnSelector', 'yourClass');

Comments

0

I know that I am late but, I happen to see this and I have a suggestion.. For those looking for cross-browser support, I wouldn't recommend class toggling via JS. It may be a little more work but it is more supported through all browsers.

document.getElementById("myButton").addEventListener('click', themeswitch);

function themeswitch() {
  const Body = document.body
  if (Body.style.backgroundColor === 'white') {
    Body.style.backgroundColor = 'black';
  } else {
    Body.style.backgroundColor = 'white';
  }
}
body {
  background: white;
}
<button id="myButton">Switch</button>

Comments

0
function navbarToggler() {
  const collapseBtn = document.querySelector('.collapseBtn').classList
  collapseBtn.toggle('collapse')
}

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.