A simple way to sort HTML lists / localeCompare()
11 Apr 2020
Something you see asked all the time is how to sort an HTML list. There's no built-in support for this, of course, and over the years there's been implementations and plugins, notably a plethora of jQuery plugins when jQuery was big.
Here's how I do it, with just a few lines of code!
let list = document.querySelector('ul#mylist'); let orderedLIs = [...list.children].sort((a, b) => a.textContent.localeCompare(b.textContent) ); list.innerHTML = orderedLIs.map(li => li.outerHTML).join('');
So what's actually happening? Well, first we grab our list element. Then we derive an array from its child element nodes. We do this by feeding children, which is an HTML collection, to a new array via spread syntax. This effectively converts it from an object to an array, and means we can use
Array.sort() on the items in it - specifically, sorting based on the text content of each child node.
We do that via
li tag) and appending the whole thing back to our list item.
An ode to String.localeCompare()
Computational sorting is a fascinating subject and most of it is off-topic for this article. Suffice is it to say, though, that the ECMAScript specification doesn't actually specify which sorting algorithm (and there are lots) a browser should use, nor whether the algorithm should be stable.
So it is that different browsers use different algorithms. For a good period, Chrome's V8 engine even used two different algorithms depending on how many elements you had in your array.
Array.sort(). Your job is only to pass it a callback function, accepting two params, which will be populated by items from the array that are then compared in your callback. The typical implementation looks like this:
The problem is, as non-English-speaking developers everywhere know and as this blog post illustrates, this fails for pretty much all languages except English. As the author says:
According to the rules, the German Umlauts (ä, ö, ü) should come right after their respective vowels: a, ä, b, o, ö. But here's where we're facing a problem, because "ä" > "b". You see, the unicode of b is 0x62 and ä is 0xE4 and 0x62 < 0xE4.
Array.sort(), with the standard implementation shown above, will put these German letters in the wrong order:
This is where
String.localeCompare() comes in.
String.localeCompare() uses locale-based character ordering rather than Unicode ordering. It compares a subject string against a comparator string, and returns a negative, positive or zero number depending on whether the subject is "before", "after" or identical to the comparator, like so:
'b'.localeCompare('c'); //-1 - b is before c 'b'.localeCompare('a'); //1 - b is after a 'b'.localeCompare('b'); //0 - b === b
It's crucial to understand that, by default,
String.localeCompare() sorts according to the user's OS-level locale. So different users in different countries may see different sort orders when they access your script - unless, that is, you enforce a language via the second argument:
Don't rely on the method returning exactly -1 or 1! The spec requires only that the method return a negative, positive or zero number, so a browser implementation could, in theory, return -2 rather than -1.
Let's try the German example again with this method:
Success! So there you have it. A brief demo of sorting list elements turned into a segue about the joys of
Did I help you? Feel free to be amazing and buy me a coffee on Ko-fi!