Skip to main content

How to Sort an Array of Strings While Ignoring Case in JavaScript

When you sort an array of strings in JavaScript using the default Array.prototype.sort() method, it performs a case-sensitive sort based on Unicode code points. This leads to the unintuitive result where all uppercase letters come before all lowercase letters (e.g., 'Z' comes before 'a').

To achieve a natural, case-insensitive alphabetical sort, you must provide a custom comparison function to the sort() method that uses String.prototype.localeCompare().

The Core Problem: Default Sort is Case-Sensitive

The default sort() method does not produce a natural alphabetical order when dealing with mixed-case strings.

Example of problem:

// Problem: The default sort is not what we want.
let letters = ['Z', 'c', 'a', 'B'];
letters.sort();

console.log(letters); // Output: ['B', 'Z', 'a', 'c']
// Uppercase letters are grouped before lowercase letters.
note

This happens because the Unicode value for 'Z' is less than the value for 'a'. To fix this, we need to tell sort() how to compare the strings in a case-insensitive way.

The String.prototype.localeCompare() method is the standard, modern, and most robust way to compare strings according to locale-specific rules. It has built-in options to handle case sensitivity.

By providing a comparison function to sort() that uses localeCompare(), we can achieve a natural, case-insensitive sort.

let letters = ['Z', 'c', 'a', 'B'];

letters.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }));

console.log(letters); // Output: ['a', 'B', 'c', 'Z']
note

This is the recommended best practice for sorting strings in JavaScript.

How localeCompare() Works for Case-Insensitive Sorting

The a.localeCompare(b, locales, options) method is designed for sophisticated string comparison. The key for our use case is the options object.

  • sensitivity: 'base': This is the crucial option. It tells localeCompare to only consider differences in the base letters. It ignores differences in case ('a' is treated as equal to 'A') and accents ('a' is treated as equal to 'á').

The localeCompare() method returns a number that the sort() method can use to determine the order:

  • Negative: a should come before b.
  • Positive: b should come before a.
  • Zero: a and b are equal for sorting purposes.

This return value is perfectly compatible with the sort() method's requirements, making localeCompare the ideal tool.

A Note on Mutability (Creating a Copy First)

The Array.prototype.sort() method sorts an array in place, meaning it mutates (modifies) the original array. This can lead to unexpected bugs if other parts of your code rely on the original order.

note

Recommended Best Practice: Always create a shallow copy of the array before sorting it if you do not intend to modify the original. The easiest way to do this is with the spread syntax (...).

let originalArray = ['Z', 'c', 'a', 'B'];

// Create a copy before sorting to preserve the original.
let sortedArray = [...originalArray].sort((a, b) =>
a.localeCompare(b, undefined, { sensitivity: 'base' })
);

console.log(sortedArray); // Output: ['a', 'B', 'c', 'Z']
console.log(originalArray); // Output: ['Z', 'c', 'a', 'B'] (Unchanged)

Conclusion

To achieve a natural, case-insensitive sort of a string array, the default sort() method is not enough.

  • The recommended best practice is to provide a custom comparison function to sort() that uses the localeCompare() method with the sensitivity: 'base' option:
    myArray.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }));
  • Always create a copy of your array (e.g., with [...arr]) before sorting if you want to avoid mutating the original data.