119

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*"); 

14 Answers 14

122

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(); 
Sign up to request clarification or add additional context in comments.

5 Comments

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: (gist.github.com/2881585)
+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.
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(" "));
A more valid solution uses map: $e.attr('class', $.map($e.attr('class').split(' '), function (klass) { return klass.indexOf(prefix) != 0 ? klass : undefined; }).join(' '));
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(" "));.
63

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

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

3 Comments

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
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.
This method can still be used with a better regex, such as the one found here: stackoverflow.com/a/2644364/1333402
33

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

$( '#foo' ).alterClass( 'foo-* bar-*', 'foobar' ) 

Comments

14

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

var el = document.getElementById("a"); // or $("#a")[0] el.className = el.className.replace(/\bbg.*?\b/g, ''); 

--UPDATE--

You can now do this generically using classList on native elements and string.startsWith:

[...el.classList.values()] .filter(c => c.startsWith(prefix)) .forEach(c => el.classList.remove(c)); 

1 Comment

If the prefix ends with a dash, you need to change the regular expression. new RegExp('\\b' + prefix + '[\\S]*\\b', 'g')
10

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>​] 

1 Comment

Since jQuery v1.4, this is the best approach.
7

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

1 Comment

element.classList.remove.apply(element.classList, x)element.classList.remove(...x), since you’re already using arrow functions and let.
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"); 

Comments

3

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(),'');}); 

Comments

2

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, ''); 

1 Comment

In 2020, the disadvantage is jQuery.
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_'); 

1 Comment

This is nothing more than my solution with 10x more lines and a less efficient "string starts with" check :-/
1

This is a fairly old post. But I worked out a solution that worked for me.

$('[class*=classtoremove]').each(function( index ) { var classArray = $(this).attr('class').split(' '); $.each( classArray, function( key, value ) { if(value.includes('classtoremove')) { console.log(value); $('.' + value).removeClass(value); } }); }); 

Essentially it will get any class that contains classtoremove regardless what is added on the end. So it could be classtoremove234164726 or classtoremove767657576575 it will find the two classes, split all the classes then for each class thats in the array will check to see if the value includes the class to remove. it then gets that class and removes the class without having to replace or re-add anything.

$('[class*=classtoremove]').each(function( index ) { var classArray = $(this).attr('class').split(' '); $.each( classArray, function( key, value ) { if(value.includes('classtoremove')) { console.log(value + ' has been removed'); $('.' + value).removeClass(value); } }); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> <div class='classtoremove235235235 chicken omlets wrapper'></div> <div class='classtoremove354645745 chicken omlets wrapper'></div> <div class='classtoremoveesdfdfh5645 chicken omlets wrapper'></div> <div class='classtoremove3425423wdt chicken omlets wrapper'></div> <div class='classtoremovewdgrt346 chicken omlets wrapper'></div> <div class='classtoremovesdgsbfd4454 chicken omlets wrapper'></div> <div class='classtoremove45454545 chicken omlets wrapper'></div> <div class='classtoremove666eed chicken omlets wrapper'></div>

Comments

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, ''); 

Comments

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

Comments

-1

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.