248

I'm a bit out of my depth here and I'm hoping this is actually possible.

I'd like to be able to call a function that would sort all the items in my list alphabetically.

I've been looking through the jQuery UI for sorting but that doesn't seem to be it. Any thoughts?

Shog9
  • 156,901
  • 35
  • 231
  • 235
  • 7
    http://stackoverflow.com/questions/304396/what-is-the-easiest-way-to-order-a-ul-ol-in-jquery – gen_Eric Oct 15 '10 at 19:33
  • Check out [Underscore.js](http://documentcloud.github.com/underscore/#sortBy) or [Sugar.js](http://sugarjs.com/api/Array/sortBy). – Kris Khaira Mar 01 '12 at 14:21

10 Answers10

351

Something like this:

var mylist = $('#myUL');
var listitems = mylist.children('li').get();
listitems.sort(function(a, b) {
   return $(a).text().toUpperCase().localeCompare($(b).text().toUpperCase());
})
$.each(listitems, function(idx, itm) { mylist.append(itm); });

From this page: http://www.onemoretake.com/2009/02/25/sorting-elements-with-jquery/

Above code will sort your unordered list with id 'myUL'.

OR you can use a plugin like TinySort. https://github.com/Sjeiti/TinySort

Saravana
  • 37,852
  • 18
  • 100
  • 108
SolutionYogi
  • 31,807
  • 12
  • 70
  • 78
  • 6
    Can the last line be replaced with $(listitems).appendTo(mylist); ? – Amir Jun 30 '10 at 06:00
  • 26
    H. L. Menken has a quote that describes this solution: "For every problem, there is a solution that is simple, elegant, and wrong." This process runs in O(n^2) time. It's not noticable with relatively short lists, but on a list containing over 100 elements it takes 3-4 seconds to finish sorting. – Nathan Strong Dec 29 '10 at 19:19
  • 5
    @Nathan: About "For every problem, there is a solution that is simple, elegant, and wrong." - well, a wrong solution is not elegant. – Johann Philipp Strathausen Jan 04 '11 at 11:01
  • 19
    Something can be elegant and intriguing to watch, but still fail. Elegance doesn't imply success. – Jane Panda Sep 29 '11 at 14:55
  • 15
    This solution is not wrong. It answers the question. The OP did not specify that he needed to sort a list of more than 100 items. If his list will never be longer than 100 items this solution is perfectly acceptable. +1 for pointing out that the solution is slow, -1 for declaring a solution that meets the requirements as 'wrong'. – Samurai Soul Nov 11 '14 at 15:27
  • This solution is more general - if I just wanted to sort a list of values, I would use Josh's solution. But if I want to sort an array of DOM elements based on some attribute of those elements, this solution is far superior. – Jason May 04 '15 at 19:54
  • 3
    This worked for me but I did add `trim()` to handle whitespace. `return $(a).text().toUpperCase().trim().localeCompare($(b).text().toUpperCase().trim())` – Dylan Valade Mar 10 '16 at 20:01
  • Documentation for `localeCompare` can be found here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare – Ken Apr 30 '19 at 11:06
  • 2
    @NathanStrong: Which process runs in O(n^2) time? – Ry- Jun 10 '19 at 15:34
  • In this case there is no need to empty or detach the existing list. Can someone explain me why? I tried with a test file and you don't get duplicated list items, you get same but ordered. Beyond that, it works perfectly. – jmrivas Jul 21 '20 at 22:52
  • 1
    Never mind, I've already found the answer in JQuery API Documentation site. This is what I was looking for "If an element selected this way is inserted into a single location elsewhere in the DOM, it will be moved into the target (not cloned)". Source: https://api.jquery.com/append/ – jmrivas Jul 21 '20 at 23:09
  • Thanks for that link to TinySort, made my list sorting a snap. – Simon Fallai Nov 30 '22 at 16:29
104

You do not need jQuery to do this...

function sortUnorderedList(ul, sortDescending) {
  if(typeof ul == "string")
    ul = document.getElementById(ul);

  // Idiot-proof, remove if you want
  if(!ul) {
    alert("The UL object is null!");
    return;
  }

  // Get the list items and setup an array for sorting
  var lis = ul.getElementsByTagName("LI");
  var vals = [];

  // Populate the array
  for(var i = 0, l = lis.length; i < l; i++)
    vals.push(lis[i].innerHTML);

  // Sort it
  vals.sort();

  // Sometimes you gotta DESC
  if(sortDescending)
    vals.reverse();

  // Change the list on the page
  for(var i = 0, l = lis.length; i < l; i++)
    lis[i].innerHTML = vals[i];
}

Easy to use...

sortUnorderedList("ID_OF_LIST");

Live Demo →

Josh Stodola
  • 81,538
  • 47
  • 180
  • 227
  • 32
    One problem that I found with this approach is that, since it's only the text that's being moved around, if you associate data to the DOM nodes using jQuery.data prior to sorting, those associations are now pointing to the wrong nodes after the sort. – Rudism Oct 28 '11 at 13:57
  • 1
    @Rudism If you're using jQuery, refer to SolutionYogi's answer below – Josh Stodola Oct 28 '11 at 15:38
  • Note that `var lis = ul.children` should suffice here (and is far more efficient). Also note that `lis[i].textContent` is preferred (as it's more efficient and get's the actual text). – Raynos Jan 16 '12 at 12:51
  • Attention down-voters: I would like to encourage you to run some tests before you make a haphazard judgement. This is not as bad as it looks, believe me! – Josh Stodola Jul 07 '12 at 05:25
  • 14
    Moving elements with innerHTML is a bad solution because they are not the same elements after sorting. All existing references to the elements are lost. All event listeners bound from JavaScript are lost. It would be better to store the elements instead of innerHTML, use a sort function (vals.sort(function(a, b) {return b.innerHTML < a.innerHTML;})) and appendChild to move elements. – gregers Sep 25 '12 at 08:35
  • 4
    Buhuuu innerHTML ! Don't use that. It's Microsoft Proprietary stuff and was never acknowledged by the W3C. – Stephan Kristyn Oct 24 '12 at 12:28
  • 14
    IMHO this is a horrible answer. It's perfectly possible to rearrange DOM nodes without serialising them and deserialising them again, and without destroying any attached properties and/or events. – Alnitak Jan 25 '13 at 22:45
  • If you want to sort `
  • One
  • ` type lists by the content within the `` tag, simply change this line `var lis = ul.getElementsByTagName("LI");` to `var lis = ul.getElementsByTagName("a");` – Federico Apr 30 '13 at 00:32
  • This works fine if you have anything but text inside your list-items. Otherwise it gets confused and doesn't sort correctly. – mroncetwice Dec 17 '14 at 22:54
  • It really only makes sense if you are just using one tag inside of another but if you are using A tags you cannot simply search for the a tags because you could have some lited items that are not links. – Coded Container Aug 03 '15 at 19:17
  • 4
    ... but if you were to use jQuery, how would you do it? – Matthew Oct 26 '15 at 18:24
  • 1
    This answer is disastrous for DOM elements that have state attached (i.e events and data). The functions `Node.removeChild()` and and `Node.insertBefore()` exist for a reason. – Nick Bedford May 03 '17 at 23:57
  • 1
    This is a more robust answer that preserves data and attributes: https://stackoverflow.com/questions/304396/what-is-the-easiest-way-to-order-a-ul-ol-in-jquery – Crashalot Jun 25 '19 at 00:02