I have an array of strings I need to sort in JavaScript, but in a case-insensitive way. How to perform this?
15 Answers
In (almost :) a one-liner
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
Which results in
[ 'bar', 'Foo' ]
While
["Foo", "bar"].sort();
results in
[ 'Foo', 'bar' ]

- 18,802
- 8
- 49
- 60
-
10Do mind that localeCompare's advanced options are not yet supported on all platforms/browsers. I know they are not used in this example, but just wanted to add for clarity. [See MDN for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare) – Ayame__ Jan 09 '14 at 15:05
-
136If you're going to involve localeCompare(), you could just use *its* ability to be case-insensitive, e.g.: `return a.localeCompare(b, 'en', {'sensitivity': 'base'});` – Michael Dyck Jul 30 '14 at 21:47
-
4+1 for not calling `toLowerCase()` when `localeCompare` already does that by default in some cases. You can read more about the parameters to pass to it here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare#Parameters – Milimetric Sep 12 '14 at 15:26
-
4@Milimetric accord to the referenced page, that feature is not supported by some browsers (eg. IE<11 or Safari). the solution mentioned here is very good, but would still require backporting/polyfill for some browsers. – 3k- Apr 06 '15 at 14:18
-
@MichaelDyck That's such an inefficient way of doing sorting though. You're calling a (likely) complex function (`localeCompare`) that even takes an object as a parameter. Calling that multiple times per item per sort call is going to make and already expensive operation (sorting) that much slower. – Slight Feb 08 '17 at 19:51
-
localeCompare is case sensitive :- ```var items = ["a", "b", "A", "B", "Z", "z"]; items.sort((a, b) => a.localeCompare(b)); [ 'a', 'A', 'b', 'B', 'z', 'Z' ]``` – Anand Sep 26 '17 at 04:51
-
2If you have a large array, it makes sense to use `items.sort(new Intl.Collator('en').compare)` for better performance. (See [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Collator).) – Valtteri Laitinen Apr 03 '18 at 10:00
-
2When sorting multiple times, you should reuse the collator: `let collator = new Intl.Collator('en'); items.sort(collator.compare)` – Valtteri Laitinen Apr 03 '18 at 10:10
-
12019: [CanIUse](https://www.caniuse.com/#search=localeCompare) shows wide adoption of `localeCompare`, **however** if your data is in English anyway, consider and test the @ron tornambe answer below before deciding. In my tests of 6,000+ items, the `return a.localeCompare(b, 'en', {'sensitivity': 'base'});` method in the comment above is slow af compared to using `toLowerCase()` alone. [YMMV](https://www.urbandictionary.com/define.php?term=ymmv) and this is a **very** dataset dependent opinion. If your data is internationally sourced, you likely MUST use `localeCompare`. _Just test a bit._ – Geek Stocks Jan 29 '19 at 22:32
-
`["Foo", "bar"].sort((a, b) => a.localeCompare(b))` for the one-liner, it will work as desired for most use cases – ignapas Dec 09 '22 at 13:48
It is time to revisit this old question.
You should not use solutions relying on toLowerCase
. They are inefficient and simply don't work in some languages (Turkish for instance). Prefer this:
['Foo', 'bar'].sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))
Check the documentation for browser compatibility and all there is to know about the sensitivity
option.

- 7,244
- 3
- 31
- 39
-
1
-
1Seems as if localCompare now is supported by all browsers except that some mobile browser do not support the 2 optional parameters: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare#Browser_compatibility – Andreas Nov 24 '20 at 11:37
-
4It looks like `['Foo', 'bar'].sort((a,b) => a.localeCompare(b))` also works – Ollie Williams Apr 19 '21 at 11:27
-
2@Ollie Williams without the locales and options arguments, the locale and sort order used are entirely implementation-dependent – ZunTzu Apr 19 '21 at 16:33
-
Documentation for the sensitivity option: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator/Collator#options – premek.v Jan 12 '23 at 17:54
myArray.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
EDIT: Please note that I originally wrote this to illustrate the technique rather than having performance in mind. Please also refer to answer @Ivan Krechetov for a more compact solution.

- 10,452
- 7
- 33
- 60
-
3This can call `toLowerCase` twice on each string; would be more efficient to stored lowered versions of the string in variables. – Jacob Aug 06 '13 at 17:23
-
True and thanks. I wrote this with clarity in mind, not performance. I guess I should note that. – ron tornambe Aug 06 '13 at 19:00
-
1@Jacob To be fair the accepted answer has same basic problem: it can possibly call `.toLowerCase()` multiple times for each item in array. For example, 45 calls to the compare function when sorting 10 items in reverse order. `var i = 0; ["z","y","x","w","v","u","t","s","r","q"].sort(function (a, b) {++i; return a.toLowerCase().localeCompare(b.toLowerCase());}); console.log("Calls to Compare: " + i); // i === 45` – nothingisnecessary Dec 20 '16 at 21:44
ES6 version:
["Foo", "bar"].sort(Intl.Collator().compare)
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Collator/compare

- 6,651
- 3
- 42
- 46
arr.sort(function(a,b) {
a = a.toLowerCase();
b = b.toLowerCase();
if (a == b) return 0;
if (a > b) return 1;
return -1;
});

- 23,026
- 8
- 58
- 72

- 320,036
- 81
- 464
- 592
-
1
-
1This will likely not work *as intended* for strings that represent numbers. The arithmetic operators will use the semantics of numbers instead of strings. E.g. if we have `["111", "33"]`, we might want it to return `["111", "33"]` because 1 comes before 3 in character code ordering. However, the function in this answer will return `["33", "111"]` because the number `33` is less than the number `111`. – Austin Davis Jun 06 '20 at 08:10
-
@AustinDavis `"33" > "111" === true` and `33 > 111 === false`. It works as intended. – Niet the Dark Absol Jun 06 '20 at 11:04
You can also use the new Intl.Collator().compare
, per MDN it's more efficient when sorting arrays. The downside is that it's not supported by older browsers. MDN states that it's not supported at all in Safari. Need to verify it, since it states that Intl.Collator
is supported.
When comparing large numbers of strings, such as in sorting large arrays, it is better to create an Intl.Collator object and use the function provided by its compare property
["Foo", "bar"].sort(Intl.Collator().compare); //["bar", "Foo"]

- 8,109
- 4
- 36
- 50

- 10,150
- 3
- 52
- 76
If you want to guarantee the same order regardless of the order of elements in the input array, here is a stable sorting:
myArray.sort(function(a, b) {
/* Storing case insensitive comparison */
var comparison = a.toLowerCase().localeCompare(b.toLowerCase());
/* If strings are equal in case insensitive comparison */
if (comparison === 0) {
/* Return case sensitive comparison instead */
return a.localeCompare(b);
}
/* Otherwise return result */
return comparison;
});

- 1,525
- 1
- 18
- 32
You can also use the Elvis operator:
arr = ['Bob', 'charley', 'fudge', 'Fudge', 'biscuit'];
arr.sort(function(s1, s2){
var l=s1.toLowerCase(), m=s2.toLowerCase();
return l===m?0:l>m?1:-1;
});
console.log(arr);
Gives:
biscuit,Bob,charley,fudge,Fudge
The localeCompare method is probably fine though...
Note: The Elvis operator is a short form 'ternary operator' for if then else, usually with assignment.
If you look at the ?: sideways, it looks like Elvis...
i.e. instead of:
if (y) {
x = 1;
} else {
x = 2;
}
you can use:
x = y?1:2;
i.e. when y is true, then return 1 (for assignment to x), otherwise return 2 (for assignment to x).

- 725
- 7
- 17
-
5To be pedantic, this isn't the Elvis operator. This is just a basic ternary operator. A true Elvis operator is null-coalescing, e.g., instead of `x = y ? y : z`, you can do `x = y ?: z`. Javascript doesn't have an actual Elvis operator, but you can use `x = y || z` in a similar fashion. – Charles Wood May 03 '18 at 15:27
Normalize the case in the .sort()
with .toLowerCase()
.
The other answers assume that the array contains strings. My method is better, because it will work even if the array contains null, undefined, or other non-strings.
var notdefined;
var myarray = ['a', 'c', null, notdefined, 'nulk', 'BYE', 'nulm'];
myarray.sort(ignoreCase);
alert(JSON.stringify(myarray)); // show the result
function ignoreCase(a,b) {
return (''+a).toUpperCase() < (''+b).toUpperCase() ? -1 : 1;
}
The null
will be sorted between 'nulk' and 'nulm'. But the undefined
will be always sorted last.

- 10,274
- 3
- 79
- 79
-
-
Guess I should've looked up the definition of `Array.prototype.sort` :| because the part about `(''+notdefined) === "undefined"` *really is* true... which means if you flip the -1 and 1 in the sort function to reverse the order, undefined still sorts to the end. It also needs to be considered when using the comparison function outside the context of an array sort (as I was when I came upon this question). – MattW Sep 15 '16 at 18:05
-
And having now pondered that `Array.prototype.sort` definition - couple more comments. First, there's no need for the `(''+a)` - ECMAScript requires `toString()` to be called on elements prior to passing them into compareFn. Second, the fact that `ignoreCase` returns `1` when comparing equal (including equal-but-for-case) strings means the specification doesn't define the result if there are duplicate values (will probably be fine just with some unnecessary swaps occurring, I think). – MattW Sep 15 '16 at 18:26
-
@MattW, It seems to me that `undefined` is a special case, which for *any x* x
undefined are **both false**. That `undefined` is always last, is a byproduct of the sort implementation of sort. I tried to change the (''+a) to simply a, but it fails. i get `TypeError: a.toUpperCase is not a function`. Apparently `toString` is **not** called prior to calling compareFn. – John Henckel Sep 15 '16 at 18:56 -
Damn my reading is bad today, `toString` only happens when `compareFn` is `undefined` (native sort). The `undefined` handling is not a natural consequence of `<` and `>` though - it's *definitely* the case that the specification of `sort` requires `undefined` to be specially handled before reaching the steps where it would normally either call `compareFn` or do its native comparison. – MattW Sep 15 '16 at 19:30
-
1Ah, ok, that makes perfect sense. For `undefined` the compareFn is **never called** – John Henckel Sep 15 '16 at 21:09
arr.sort(function(a,b) {
a = a.toLowerCase();
b = b.toLowerCase();
if( a == b) return 0;
if( a > b) return 1;
return -1;
});
In above function, if we just compare when lower case two value a and b, we will not have the pretty result.
Example, if array is [A, a, B, b, c, C, D, d, e, E] and we use the above function, we have exactly that array. It's not changed anything.
To have the result is [A, a, B, b, C, c, D, d, E, e], we should compare again when two lower case value is equal:
function caseInsensitiveComparator(valueA, valueB) {
var valueALowerCase = valueA.toLowerCase();
var valueBLowerCase = valueB.toLowerCase();
if (valueALowerCase < valueBLowerCase) {
return -1;
} else if (valueALowerCase > valueBLowerCase) {
return 1;
} else { //valueALowerCase === valueBLowerCase
if (valueA < valueB) {
return -1;
} else if (valueA > valueB) {
return 1;
} else {
return 0;
}
}
}

- 510
- 6
- 19
In support of the accepted answer I would like to add that the function below seems to change the values in the original array to be sorted so that not only will it sort lower case but upper case values will also be changed to lower case. This is a problem for me because even though I wish to see Mary next to mary, I do not wish that the case of the first value Mary be changed to lower case.
myArray.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
In my experiments, the following function from the accepted answer sorts correctly but does not change the values.
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});

- 249
- 3
- 11
This may help if you have struggled to understand:
var array = ["sort", "Me", "alphabetically", "But", "Ignore", "case"];
console.log('Unordered array ---', array, '------------');
array.sort(function(a,b) {
a = a.toLowerCase();
b = b.toLowerCase();
console.log("Compare '" + a + "' and '" + b + "'");
if( a == b) {
console.log('Comparison result, 0 --- leave as is ');
return 0;
}
if( a > b) {
console.log('Comparison result, 1 --- move '+b+' to before '+a+' ');
return 1;
}
console.log('Comparison result, -1 --- move '+a+' to before '+b+' ');
return -1;
});
console.log('Ordered array ---', array, '------------');
// return logic
/***
If compareFunction(a, b) is less than 0, sort a to a lower index than b, i.e. a comes first.
If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behaviour, and thus not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.
If compareFunction(a, b) is greater than 0, sort b to a lower index than a.
***/

- 4,376
- 2
- 35
- 55
I wrapped the top answer in a polyfill so I can call .sortIgnoreCase() on string arrays
// Array.sortIgnoreCase() polyfill
if (!Array.prototype.sortIgnoreCase) {
Array.prototype.sortIgnoreCase = function () {
return this.sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
};
}

- 4,521
- 2
- 32
- 36
-
1Please never ever do this. Only modify the prototype of things you own. This is also not a polyfill, as this Array method is nowhere in the ECMAScript specs. – Joe Maffei Jun 19 '19 at 20:15