171

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();
});
jarrodwhitley
  • 826
  • 10
  • 29
max imax
  • 2,131
  • 3
  • 15
  • 16

13 Answers13

281

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

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
  • if we can't use IDs, then how ca we do that? – Goku Mar 12 '15 at 20:36
  • but, then we will have the same classes quantity instead old IDs, and use something like var myList = document.getElementsByClassName("abc") ? – Goku Mar 12 '15 at 21:09
  • 1
    @goku classes don't appear underneath the window object. Only IDs do. See http://www.2ality.com/2012/08/ids-are-global.html – mikemaccana Mar 13 '15 at 11:44
  • 1
    Supported by IE10 and IE11 except for the second parameter – Below the Radar Apr 06 '18 at 12:44
  • 1
    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'); } – Blue Tram Feb 01 '19 at 03:52
  • @BlueTram You can just do `nodeList.forEach()` these days. – mikemaccana Mar 05 '21 at 16:55
27

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
Gor
  • 1,385
  • 12
  • 7
  • 4
    ES6 is great, but this solution is simply using 'document.querySelector' and 'element.classList.toggle' per the other existing answers. – mikemaccana Dec 17 '18 at 15:34
  • No solution is valid if it is "vendor oriented", **Internet is open-standard-oriented**. – Peter Krauss Mar 29 '20 at 18:45
  • 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! ) –  Jun 15 '20 at 15:05
11

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;
}
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>
Balaji
  • 9,657
  • 5
  • 47
  • 47
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>
Community
  • 1
  • 1
rrk
  • 15,677
  • 4
  • 29
  • 45
  • 1
    `\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'` !! – S.Serpooshan Feb 05 '19 at 06:47
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)

Jyoti
  • 116
  • 3
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(' ');
}
mushishi78
  • 355
  • 3
  • 10
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');
hejdav
  • 1,267
  • 15
  • 19
  • 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. – Rob Waa Jan 31 '22 at 18:36
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`
Mike Pelley
  • 2,939
  • 22
  • 23
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');
Christiyan
  • 485
  • 5
  • 5
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 += " ";
            }
        }
    }
}
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>
Seth M.
  • 11
  • 4
0
function navbarToggler() {
  const collapseBtn = document.querySelector('.collapseBtn').classList
  collapseBtn.toggle('collapse')
}
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Abass Dev
  • 71
  • 6
  • 2
    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](/help/how-to-answer). – Community Nov 30 '21 at 15:55