DEV Community

Corey Ward
Corey Ward

Posted on • Originally published at coreyward.svbtle.com

Case Sensitivity with `localeCompare` in JavaScript

I recently ran into a bug using code like the following:

someArray.sort((a, b) => a.name.localeCompare(b.name))
Enter fullscreen mode Exit fullscreen mode

At a glance this seems fine—localCompare enjoys fantastic browser support, and as the name suggests, it isn’t English-centric. However, this is still the web we’re building for, and the familiar gotcha of inconsistent behavior amongst browsers is lurking here. This can lead to hard-to-debug inconsistencies and bugs.

Most browsers—including Chrome, Edge, and Firefox—and Node treat localeCompare as case-insensitive by default, treating an uppercase “A” as the same as a lowercase “a”. Safari, however, does something different.

Safari uses a variant of case-sensitive sorting, but not in the usual ASCII order where “Z” sorts above “a”. Instead Safari sorts lowercase letters above their uppercase companions, but in alphabetical order otherwise, like “aAbBcC”. In many cases this is fine—sorting based on the user’s locale is not only acceptable, it’s preferable. But as you may suspect given the title, that’s not always true.

In scenarios where data is expected to match the order from a server, such as when sorting properties before hashing for verification or as a checksum, or when hydrating server-side rendered React, this behavior becomes troublesome. In these cases, consistent behavior across environments is critical to prevent bugs. Thankfully, this can be achieved by specifying a few additional options to localeCompare:

a.name.localeCompare(b.name, "en", { sensitivity: "base" })
Enter fullscreen mode Exit fullscreen mode

First, we’re specifying an expected locale. This ensures the items are compared in the same locale server-side and client-side. In a localized app, this value can be localized as well, just be sure to use the same value in both environments.

The second change, adding sensitivity: "base", tells browsers to use the base character (think lowercase) for comparison (MDN), effectively making the comparison case-insensitive. This results in consistent sorting behavior across Node and all common browsers (including IE11). 🎉

Top comments (0)