117

I have a div with id="a" that may have any number of classes attached to it, from several groups. Each group has a specific prefix. In the javascript, I don't know which class from the group is on the div. I want to be able to clear all classes with a given prefix and then add a new one. If I want to remove all of the classes that begin with "bg", how do I do that? Something like this, but that actually works:

$("#a").removeClass("bg*");
bluish
  • 26,356
  • 27
  • 122
  • 180
Brad
  • 5,845
  • 7
  • 30
  • 29

16 Answers16

118

A regex splitting on word boundary \b isn't the best solution for this:

var prefix = "prefix";
var classes = el.className.split(" ").filter(function(c) {
    return c.lastIndexOf(prefix, 0) !== 0;
});
el.className = classes.join(" ").trim();

or as a jQuery mixin:

$.fn.removeClassPrefix = function(prefix) {
    this.each(function(i, el) {
        var classes = el.className.split(" ").filter(function(c) {
            return c.lastIndexOf(prefix, 0) !== 0;
        });
        el.className = $.trim(classes.join(" "));
    });
    return this;
};

2018 ES6 Update:

const prefix = "prefix";
const classes = el.className.split(" ").filter(c => !c.startsWith(prefix));
el.className = classes.join(" ").trim();
Kabir Sarin
  • 18,092
  • 10
  • 50
  • 41
  • 10
    This is better approach than using RegExp with \b (word boundary check) because it prevents 'zombie classes' from popping up. If you have classes like "prefix-suffix", the 'best answer' in this thread will leave the class '-suffix' because \b will split before '-' char. Your split-map-join solution works around that :) I created a tiny jQuery plugin around your solution, Kabir: (https://gist.github.com/2881585) – Jakub P. Jun 06 '12 at 12:32
  • 3
    +1 I as well concur, every other answer appears to just be a simple regex that would break on non-space word boundaries. If I have time tomorrow I'll supply a unit test that proves this. – gerges Jun 14 '12 at 05:10
  • 1
    I like it although this actually isn't valid code, since the anonymous function in `filter` must return a boolean. This will work: `var classes = $(e).attr("class").split(" "); $(classes).each(function(i, item) { classes[i] = item.indexOf("prefix") === -1 ? item : "prefix-new"); }); $(e).attr("class", classes.join(" "));` – Tim Oct 13 '13 at 13:43
  • A more valid solution uses map: `$e.attr('class', $.map($e.attr('class').split(' '), function (klass) { return klass.indexOf(prefix) != 0 ? klass : undefined; }).join(' '));` – M Miller Jul 07 '14 at 01:31
  • 2
    This approach works the best. I used @JakubP's plugin. One suggestion if I may: What it does, when it now returns the classes, it causes a lot of space. For instance `class="blackRow blackText orangeFace blackHead"` will return `class=" orangeFace "` if you run `removeClassPrefix("black");`. I solved this by trimming the result like so: `el.className = $.trim(classes.join(" "));`. – Bird87 ZA Jul 23 '14 at 06:35
61

With jQuery, the actual DOM element is at index zero, this should work

$('#a')[0].className = $('#a')[0].className.replace(/\bbg.*?\b/g, '');
bluish
  • 26,356
  • 27
  • 122
  • 180
Pat
  • 36,282
  • 18
  • 72
  • 87
  • 36
    Careful with this one. Word boundary splits on dash character ('-') and dots and others, so class names like "bg.a", "bg-a" etc. will not be removed but replaced with ".a", "-a" etc. So if you have classnames with punctuation characters you may run into trouble by just running a simple regex replace. Here is a SO thread [about word boundary definition](http://stackoverflow.com/questions/1324676/what-is-a-word-boundary-in-regexes) – Jakub P. Jun 06 '12 at 12:00
  • 6
    Kabir Sarin's answer below with split(' ') and indexOf is better IMO because it won't cause those special-charactered "zombie" classes to pop up. – Jakub P. Jun 06 '12 at 12:29
  • 2
    This method can still be used with a better regex, such as the one found here: http://stackoverflow.com/a/2644364/1333402 – ssmith Feb 07 '14 at 00:05
32

I've written a simple jQuery plugin - alterClass, that does wildcard class removal. Will optionally add classes too.

$( '#foo' ).alterClass( 'foo-* bar-*', 'foobar' ) 
Aliaksandr Sushkevich
  • 11,550
  • 7
  • 37
  • 44
Pete B
  • 1,709
  • 18
  • 11
13

You don't need any jQuery specific code to handle this. Just use a RegExp to replace them:

$("#a").className = $("#a").className.replace(/\bbg.*?\b/g, '');

You can modify this to support any prefix but the faster method is above as the RegExp will be compiled only once:

function removeClassByPrefix(el, prefix) {
    var regx = new RegExp('\\b' + prefix + '.*?\\b', 'g');
    el.className = el.className.replace(regx, '');
    return el;
}
Prestaul
  • 83,552
  • 10
  • 84
  • 84
  • If the prefix ends with a dash, you need to change the regular expression. `new RegExp('\\b' + prefix + '[\\S]*\\b', 'g')` – yaroslawww Jun 10 '21 at 07:57
9

Using 2nd signature of $.fn.removeClass :

// Considering:
var $el = $('<div class="  foo-1 a b foo-2 c foo"/>');

function makeRemoveClassHandler(regex) {
  return function (index, classes) {
    return classes.split(/\s+/).filter(function (el) {return regex.test(el);}).join(' ');
  }
}

$el.removeClass(makeRemoveClassHandler(/^foo-/));
//> [<div class=​"a b c foo">​</div>​]
abernier
  • 27,030
  • 20
  • 83
  • 114
5

For modern browsers:

let element = $('#a')[0];
let cls = 'bg';

element.classList.remove.apply(element.classList, Array.from(element.classList).filter(v=>v.startsWith(cls)));
Max
  • 541
  • 6
  • 9
3

An approach I would use using simple jQuery constructs and array handling functions, is to declare an function that takes id of the control and prefix of the class and deleted all classed. The code is attached:

function removeclasses(controlIndex,classPrefix){
    var classes = $("#"+controlIndex).attr("class").split(" ");
    $.each(classes,function(index) {
        if(classes[index].indexOf(classPrefix)==0) {
            $("#"+controlIndex).removeClass(classes[index]);
        }
    });
}

Now this function can be called from anywhere, onclick of button or from code:

removeclasses("a","bg");
nhahtdh
  • 55,989
  • 15
  • 126
  • 162
2

I was looking for solution for exactly the same problem. To remove all classes starting with prefix "fontid_" After reading this article I wrote a small plugin which I'm using now.

(function ($) {
        $.fn.removePrefixedClasses = function (prefix) {
            var classNames = $(this).attr('class').split(' '),
                className,
                newClassNames = [],
                i;
            //loop class names
            for(i = 0; i < classNames.length; i++) {
                className = classNames[i];
                // if prefix not found at the beggining of class name
                if(className.indexOf(prefix) !== 0) {
                    newClassNames.push(className);
                    continue;
                }
            }
            // write new list excluding filtered classNames
            $(this).attr('class', newClassNames.join(' '));
        };
    }(fQuery));

Usage:

$('#elementId').removePrefixedClasses('prefix-of-classes_');
Pawel
  • 16,093
  • 5
  • 70
  • 73
2

In one line ... Removes all classes that match a regular expression someRegExp

$('#my_element_id').removeClass( function() { return (this.className.match(/someRegExp/g) || []).join(' ').replace(prog.status.toLowerCase(),'');});
Adam111p
  • 3,469
  • 1
  • 23
  • 18
2

http://www.mail-archive.com/jquery-en@googlegroups.com/msg03998.html says:

...and .removeClass() would remove all classes...

It works for me ;)

cheers

1

I know it's an old question, but I found out new solution and want to know if it has disadvantages?

$('#a')[0].className = $('#a')[0].className
                              .replace(/(^|\s)bg.*?(\s|$)/g, ' ')
                              .replace(/\s\s+/g, ' ')
                              .replace(/(^\s|\s$)/g, '');
Jan.J
  • 3,050
  • 1
  • 23
  • 33
0
(function($)
{
    return this.each(function()
    {
        var classes = $(this).attr('class');

        if(!classes || !regex) return false;

        var classArray = [];

        classes = classes.split(' ');

        for(var i=0, len=classes.length; i<len; i++) if(!classes[i].match(regex)) classArray.push(classes[i]);

        $(this).attr('class', classArray.join(' '));
    });
})(jQuery);
Rob
  • 10,851
  • 21
  • 69
  • 109
0

I also use hyphen'-' and digits for class name. So my version include '\d-'

$('#a')[0].className = $('#a')[0].className.replace(/\bbg.\d-*?\b/g, '');
jamland
  • 931
  • 15
  • 23
0

Prestaul's answer was helpful, but it didn't quite work for me. The jQuery way to select an object by id didn't work. I had to use

document.getElementById("a").className

instead of

$("#a").className
Brad
  • 5,845
  • 7
  • 30
  • 29
0

The top answer converted to jQuery for those wanting a jQuery only solution:

const prefix = 'prefix'
const classes = el.attr('class').split(' ').filter(c => !c.startsWith(prefix))
el.attr('class', classes.join(' ').trim())
danday74
  • 52,471
  • 49
  • 232
  • 283
-6
$("#element").removeAttr("class").addClass("yourClass");
JSW189
  • 6,267
  • 11
  • 44
  • 72
  • 3
    I don't think you read the question very well. The user was not asking about simply removing a class and adding another one. – Andrew Barber Feb 13 '13 at 14:34
  • 1
    @Andrew Barber: you're right this is not the right answer, but majorsk8 suggested how to clear all the classes (removeAttr), not just a single one ;) – Tilt Sep 11 '14 at 09:54