How to write an addClass method

JavaScript polyfill, by , Wednesday, March 26th, 2014

If you do any kind of web development, I am sure you have been in situations where you needed to add one or more classes to one or more DOM elements. All libraries that are build to deal with the DOM have a feature that help you accomplice this in one way or another, but sometimes using a library is not practical or desired. In any extend it is always a good idea to know how to do this without any external help, so lets give it a try.

addClass method using nested for-loop

I am going to write the function using two for-loops and it is going to take two parameters;

  • obj which is one or more elements to which the class(es) should be added
  • cl which is either a String or an Array of classes to add.

The way it works is, that it adds the given class(es) to the element(s) if they do not already exist. This means, that if the given element already have the class we want to add, it will not be added, as there is no point in having duplicate classes on an element. Before we go into more detail lets have a look at the code;

  1. var addClass = function (obj, cl) {
  2. "use strict";
  3. var isObjClass = function (o,ocl) {
  4. return Object.prototype.toString.call(o) === '[object ' + ocl + ']';
  5. },
  6. i, j,
  7. o = isObjClass(obj, 'NodeList') ? obj : [obj],
  8. oLen = o.length,
  9. cl = isObjClass(cl, 'Array') ? cl : cl.split(' '),
  10. clLen = cl.length;
  11.  
  12. for (i = 0; i < oLen; i++) {
  13. for (j = 0; j < clLen; j++) {
  14. if (o[i].className.indexOf(cl[j]) < 0) {
  15. o[i].className += o[i].className ? ' ' + cl[j] : cl[j];
  16. }
  17. }
  18. }
  19. };

The first thing you might notice is, that I have written a small method inside the addClass, called isObjClass. The reason for this is, that we need a reliable way to check if the parameters, are of the object class Array or NodeList. We need to know this because if they are not, we need to turn them into arrays, so that we can iterate over them. Object classes are a very reliable way to determine what kind of object you are dealing with, and writing this method inside our addClass function, of course poses the question of writing a general isObjClass in your project, that you can call when needed. If you choose to do this, which is a good idea, then of course you can remove that part from the addClass function. (for more information about a general isObjClass method and about determining the class of an object value read my article How to get the class of an object value) If we pretend that we have the isObjClass method available from some outer scope, our addClass function looks more simple;

  1. var addClass = function (obj, cl) {
  2. "use strict";
  3. var i, j,
  4. o = isObjClass(obj, 'NodeList') ? obj : [obj],
  5. oLen = o.length,
  6. cl = isObjClass(cl, 'Array') ? cl : cl.split(' '),
  7. clLen = cl.length;
  8.  
  9. for (i = 0; i < oLen; i++) {
  10. for (j = 0; j < clLen; j++) {
  11. if (o[i].className.indexOf(cl[j]) < 0) {
  12. o[i].className += o[i].className ? ' ' + cl[j] : cl[j];
  13. }
  14. }
  15. }
  16. };

addClass method using forEach and recursion

Another way or writing such a function is using the build in Array.prototype.forEach method. This works in all modern browsers, but if an important part of your visitor group use an old browser such as IE8, then you can use the polyfill I have written in for the Array.prototype.forEach method. As you will see, the code using recursion is more compact, but pretty straight forward anyway.

  1. var addClass = function (obj, cl) {
  2. "use strict";
  3. var o = isObjClass(obj, 'NodeList') ? obj : [obj],
  4. cl = isObjClass(cl, 'Array') ? cl : cl.split(' ');
  5.  
  6. Array.prototype.slice.call(o).forEach(function (elmVal) {
  7. elmVal.className = (function addCls(oClass, tIndex) {
  8. return cl[tIndex] ? addCls((function () {
  9. if (oClass.indexOf(cl[tIndex]) <= 0) {
  10. oClass.push(cl[tIndex]);
  11. }
  12. return oClass;
  13. }()), tIndex + 1) : oClass.join(' ');
  14. }(elmVal.className.split(' '), 0));
  15. });
  16. };

What is going on here is that we, using the forEach method iterate over the elements given. If you read about the forEach method either on Mozillas documentation pages or in my polyfill article, you will find that the callback function gets called with three parameters; the element value, element index, and the array being traversed. We are only interested in the element value here, and as you can see in line 7 we set the current elements class name (elmVal.className) to be equal to the result of the IIFE inline function named addCls. Inside that function we first check if the current class name is a truthy value (you can read more about truthy and falsy values in my tutorial Primitive types, and truthy and falsy values), which makes sense in this scenario. If we have a valid class, we run the addCls inline function (line 8 -13) passing in the object classes along with the next index.

This is just two ways of writing such a function, but there are many more, and they can be quite fun to come up with. But feel free to use these in any way you want, code is meant to be shared.