43

I use these JavaScript-code to change classes in my script:

var toggleDirection = function() {
  group.classList.toggle('left-to-right');
  group.classList.toggle('right-to-left');
}

In my example there a only two classes to change but could be also multiple classes ...

So therefore: Does anyone know a way to write the example less redundant?

2
  • You can create your own prototype for Element => jsfiddle.net/rayon_1990/2noyz7zf Commented Apr 11, 2016 at 9:45
  • yes! Comma separated or with array in spread syntax, examples in answer below here Commented Dec 8, 2022 at 19:15

14 Answers 14

30

No it is not possible using Element.classList API directly. Looking at API you can read:

toggle ( String [, force] ) When only one argument is present: Toggle class value; i.e., if class exists then remove it, if not, then add it. When a second argument is present: If the second argument is true, add specified class value, and if it is false, remove it.

Reference here.

You could potentially write your own "utility" function (in vanilla JS) which does what you want, below a very simple demonstrative example which work on top of the classList API:

var superToggle = function(element, class0, class1) {
  element.classList.toggle(class0);
  element.classList.toggle(class1);
}

And you call it in this way:

superToggle(group,'left-to-right', 'right-to-left');
Sign up to request clarification or add additional context in comments.

Comments

25

For anyone looking for a short answer, you can do this on one line using the rest parameter introduced in ES6/ES2015:

const toggleCSSclasses = (el, ...cls) => cls.map(cl => el.classList.toggle(cl))

This is pretty close to @attacomsian's answer, but taking advantage of the fact that the rest parameter will return an array - no matter how many arguments is being passed to the function. Which means we can skip the part where we detect whether we're working with a string or an array.

const toggleCSSclasses = (el, ...cls) => cls.map(cl => el.classList.toggle(cl));

const one = document.querySelector(".one");

one.addEventListener("click", () => {
  toggleCSSclasses(one, "class1");
});

const two = document.querySelector(".two");

two.addEventListener("click", () => {
  toggleCSSclasses(two, "class1", "class2");
});
.class1 { text-decoration: underline }
.class2 { background: steelblue }
<p class="one">Click to toggle one class</p>
<p class="two">Click to toggle two classes</p>

1 Comment

Don't use map if you don't mean to produce a new array.
20

Just use the Array.forEach.

like

['left-to-right', 'right-to-left'].forEach( className => group.classList.toggle(className) )

If you start with one of these classes applied, e.g. 'left-to-right', on each toggle action, the initial class will be toggled off, while the other one will be toggled on and so forth.

1 Comment

Don't use map if you don't mean to produce a new array.
3

Here is ES6 version of solution

const classToggle = (el, ...args) => args.map(e => el.classList.toggle(e))

const classToggle = (el, ...args) => {
  args.map(e => el.classList.toggle(e))
}
.a {
  color: red
}

.b {
  background: black
}

.c {
  border-color: yellow
}
<button onclick="classToggle(this,'a', 'c','b')" class="a b c ">Click me</button>

And here's old JS code:

var classToggle = function classToggle(el) {
  for (
    var _len = arguments.length,
      args = new Array(_len > 1 ? _len - 1 : 0),
      _key = 1;
    _key < _len;
    _key++
  ) {
    args[_key - 1] = arguments[_key];
  }

  args.map(function (e) {
    return el.classList.toggle(e);
  });
};

2 Comments

This looks like the simplest answer but the code snippet does not show show yellow, just goes white to red. Also is it possible to toggle multiple divs/items/button on the same click?
Don't use map if you don't mean to produce a new array.
3

Answer from year 2020 here!

Found this article helpful from 4/2021

Can use comma separated list of classes like this:

const button = document.getElementById('button')

button.classList.add('btn', 'btn-primary', 'btn-primary--footer')
button.classList.remove('btn', 'btn-primary', 'btn-primary--footer')

or even spread syntax from a list of classes:

const button = document.getElementById('button')
const classes = ['btn', 'btn-primary', 'btn-primary--footer']

button.classList.add(...classes)
button.classList.remove(...classes)

Comments

1

If I need to toggle multiple classes I just create an array and then iterate through it.

  var classes = [
    "red",
    "blue",
    "green",
    "purple"
  ]

  for (var i = 0; i < classes.length; i++){
    p.classList.toggle(classes[i])
  }

2 Comments

This just toggles through everything and leaves it on the last one. I dont think this is what OP wanted.
@misteroptimist What do you mean by "leaves it on the last one"?
1

Assuming that myElement is a valid DOM Element, this works:

['right-to-left', 'left-to-right'].forEach(function(className){
  this.classList.toggle(className);
}, myElement);

4 Comments

I think you misunderstand the way classList.toggle() works. It does allow for a second argument, but that is used as a conditional for the first argument, which holds the class to toggle. It does not allow for two classes to be toggled at once. See developer.mozilla.org/en-US/docs/Web/API/Element/classList
@agrm Thanks for the correction. I will edit my answer shortly so that it doesn't mislead others.
@rayalois22 Can you please edit the answer? It doesn't work!
@safwan-samsudeen, I have edited my answer and the current version works well on my end. I hope someone finds it useful
1

This Worked for me

let superToggle = (element, class0, class1) => {
 element.classList.toggle(class0);
 element.classList.toggle(class1);
};

Comments

1
const toggleClasses = (e, classes) => {
  classes.forEach((className) => {
    e.classList.toggle(className)
  });
}

const classes = [
  'hidden',
  'bg-white',
]

toggleClasses(element, classes)

1 Comment

Please read How do I write a good answer?. While this code block may answer the OP's question, this answer would be much more useful if you explain how this code is different from the code in the question, what you've changed, why you've changed it and why that solves the problem without introducing others.
1

so to toggle multiple classes in javascript(ES6) you need to create a function that have 2 parameter

  1. a normal parameter
  2. a rest parameter which will take in all the classes you want

here is the code for it i hope it work you

let domElemet = document.getElementById("Dom-element-to-toggle-classe");

function toggleClassNames(element, ...ClassNames) {
ClassNames.forEach((Class) => element.classList.toggle(Class));
}

toggleClassNames(domElemet, "left-to-right", "right-to-left");

Comments

1

There is no direct way but you can create a helper function:

const toggleClass =  (el, cls) => {
    if (Array.isArray(cls)) {
        cls.forEach((cl) => {
            el.classList.toggle(cl);
        });
    } else {
        el.classList.toggle(cls);
    }
};

Now just call toggleClass() like below:

// single class
toggleClass(document.querySelector('body'), 'left-to-right');
//multiple classes
toggleClass(document.querySelector('body'), ['left-to-right', 'right-to-left']);

2 Comments

Don't use map if you don't mean to produce a new array.
@Bergi, you are right. I switched it to forEach.
0

The following should work; granted that these class-names are defined in your CSS and some elements on the current page have these classNames:

var toggleDirection = function()
{
    var ltr, rtl, lst, cls;

    ltr = 'left-to-right';
    rtl = 'right-to-left';
    lst = [].slice.call(document.getElementsByClassName(ltr));

    lst = ((lst.length > 0) ? lst : [].slice.call(document.getElementsByClassName(rtl)));

    lst.forEach
    (
        function(node)
        {
            cls = node.getAttribute('class');

            if (cls.indexOf(ltr) > -1)
            { cls.split(ltr).join(rtl); }
            else
            { cls.split(rtl).join(ltr); }

            node.setAttribute('class', cls);
        }
    );
}

Comments

0

You can extend the DOMTokenList object with the following multiToggle

if (window["DOMTokenList"]) //check if DOMTokenList is an existing object.
{
//multitoggle
DOMTokenList.prototype.multiToggle = function()
{
    if (arguments.length > 0) // there needs to be at least one object
    {
        for (argument in arguments) //loop all arguments
        {
            var argument = arguments[argument];
            //All primitives are allowed as input (Symbol not included). If not a primitive, raise error.
            if (Object.prototype.toString.call(argument) !== "[object Undefined]" && Object.prototype.toString.call(argument) !== "[object Null]" && Object.prototype.toString.call(argument) !== "[object String]" && Object.prototype.toString.call(argument) !== "[object Number]" && Object.prototype.toString.call(argument) !== "[object Boolean]")   
            {
                throw new SyntaxError;
            }
            else
            {
                if (this.contains(argument)) //check if classList contains the argument.
                {
                    this.remove(argument); //if so remove
                }
                else
                {
                    this.add(argument); //if not add
                }                   
            }
        }
    }
    else
    {
        throw new Error("The argument is not optional");
    }
    return undefined; //return undefined as with add and remove.
}       
}

multiToggle does not have the force ability of the original toggle. It just turns class names on and off for as many arguments as supplied.

Warning, expanding fixed Objects can cause troubles in the future . When an object gets deprecated or changed your functionality could break, requiring to more maintenance.

Comments

0

If you like the simple one liner of using classList.toggle this solution assumes you are using the optional condition (true/false) which is the 2nd parameter:

classList.toggle(class, true/false)

This solution dynamically uses add or remove method of classList as those methods allow for multiple classes.
Solution:

el.classList[(condition === true ? 'add' : 'remove')]('left-to-right', 'right-to-left')

Comments

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.