There are many ways to sort and arrange content within an array or list, generally in ascending or descending ways. Here are the most basic ones.
Array.sort()
01. sort() — the Default Sort’s Trap
sort() mutates the array in place and, by default, compares items as strings. That’s fine for words, but a trap for numbers.
<div class="chips" id="sb-chips"></div><button class="btn" id="sb-sort">array.sort()</button><div class="out" id="sb-out">Click to sort — guess the order first!</div>
const chips = document.getElementById("cf-chips");const out = document.getElementById("cf-out");if (chips && out) { const original = [40, 100, 21, 5, 9]; const render = (arr, label) => { chips.innerHTML = arr.map((n) => `<div class="chip">${n}</div>`).join(""); out.textContent = label; }; render(original, "click a button to sort"); document.getElementById("cf-asc").onclick = () => { document.getElementById("cf-asc").classList.add("active"); document.getElementById("cf-desc").classList.remove("active"); const sorted = [...original].sort((a, b) => a - b); render(sorted, `[...arr].sort((a, b) => a - b) -> [${sorted.join(", ")}]`); }; document.getElementById("cf-desc").onclick = () => { document.getElementById("cf-desc").classList.add("active"); document.getElementById("cf-asc").classList.remove("active"); const sorted = [...original].sort((a, b) => b - a); render(sorted, `[...arr].sort((a, b) => b - a) -> [${sorted.join(", ")}]`); };}
const nums = [40, 100, 21, 5, 9]const ascending = [...nums].sort((a, b) => a - b) // [5, 9, 21, 40, 100]const descending = [...nums].sort((a, b) => b - a) // [100, 40, 21, 9, 5]// spread (...nums) copies the array first — sort() mutates otherwise!
03. Sorting Strings
Default string sort compares character codes — uppercase letters (A–Z) all come before lowercase (a–z). Use .toLowerCase() with localeCompare to sort the way people expect.
const products = [ { name: "Mug", price: 12 }, { name: "Notebook", price: 5 }, { name: "Backpack", price: 45 },]products.sort((a, b) => a.name.localeCompare(b.name)) // alphabetical by nameproducts.sort((a, b) => a.price - b.price) // cheapest firstproducts.sort((a, b) => b.price - a.price) // priciest first
Sorting Algorithms
Built-in sort() is what you’ll use in real code — but it helps to understand what an actual sorting algorithm does under the hood.
05. Bubble Sort — Step by Step
Bubble sort repeatedly compares neighbors and swaps them if they’re in the wrong order — the largest values “bubble up” to the end. It’s slow (O(n²)) but the easiest algorithm to understand.
<div class="bars" id="bs-bars"></div><div class="btns"> <button class="btn" id="bs-next">Next step</button> <button class="btn" id="bs-reset">Reset</button></div><div class="out" id="bs-out">Click "Next step" to compare the first pair</div>
const barsEl = document.getElementById("bs-bars");const out = document.getElementById("bs-out");if (barsEl && out) { const initial = [8, 3, 10, 5, 1]; const n = initial.length; const buildSteps = (input) => { const arr = [...input]; const steps = []; let sortedCount = 0; for (let i = 0; i < n - 1; i++) { for (let j = 0; j < n - 1 - i; j++) { const swapped = arr[j] > arr[j + 1]; if (swapped) [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; if (j === n - 2 - i) sortedCount++; steps.push({ j, swapped, sortedCount, snapshot: [...arr] }); } } steps.push({ done: true, sortedCount: n, snapshot: [...arr] }); return steps; }; const steps = buildSteps(initial); let idx = -1; const render = () => { const snap = idx < 0 ? initial : steps[idx].snapshot; const step = idx < 0 ? null : steps[idx]; barsEl.innerHTML = snap .map((v, i) => { let cls = "bar"; if (step) { if (step.done || i >= n - step.sortedCount) cls += " sorted"; else if (i === step.j || i === step.j + 1) cls += " compare"; } return `<div class="${cls}" style="height:${v * 10}px">${v}</div>`; }) .join(""); }; render(); document.getElementById("bs-next").onclick = () => { if (idx >= steps.length - 1) return; idx++; const step = steps[idx]; render(); out.textContent = step.done ? "Sorted! ✅" : `compare arr[${step.j}] and arr[${step.j + 1}] -> ${step.swapped ? "swap" : "no swap"}`; }; document.getElementById("bs-reset").onclick = () => { idx = -1; render(); out.textContent = 'Click "Next step" to compare the first pair'; };}
function bubbleSort(arr) { const result = [...arr] for (let i = 0; i < result.length - 1; i++) { for (let j = 0; j < result.length - 1 - i; j++) { if (result[j] > result[j + 1]) { // swap neighbors ;[result[j], result[j + 1]] = [result[j + 1], result[j]] } } } return result}bubbleSort([8, 3, 10, 5, 1]) // [1, 3, 5, 8, 10]
06. Selection Sort — Step by Step
Selection sort scans the unsorted part of the array to find the minimum, then swaps it into place at the front. Fewer swaps than bubble sort, but still O(n²).
<div class="bars" id="ss2-bars"></div><div class="btns"> <button class="btn" id="ss2-next">Next step</button> <button class="btn" id="ss2-reset">Reset</button></div><div class="out" id="ss2-out">Click "Next step" to scan for the minimum</div>
const barsEl = document.getElementById("ss2-bars");const out = document.getElementById("ss2-out");if (barsEl && out) { const initial = [6, 2, 9, 1, 5]; const n = initial.length; const buildSteps = (input) => { const arr = [...input]; const steps = []; for (let i = 0; i < n - 1; i++) { let minIdx = i; for (let j = i + 1; j < n; j++) { if (arr[j] < arr[minIdx]) minIdx = j; steps.push({ type: "compare", i, j, minIdx, snapshot: [...arr] }); } if (minIdx !== i) [arr[i], arr[minIdx]] = [arr[minIdx], arr[i]]; steps.push({ type: "swap", i, minIdx, snapshot: [...arr] }); } steps.push({ type: "done", i: n, snapshot: [...arr] }); return steps; }; const steps = buildSteps(initial); let idx = -1; const render = () => { const snap = idx < 0 ? initial : steps[idx].snapshot; const step = idx < 0 ? null : steps[idx]; barsEl.innerHTML = snap .map((v, i) => { let cls = "bar"; if (step) { if (step.type === "done" || i < step.i) cls += " sorted"; else if (step.type === "compare" && (i === step.j || i === step.minIdx)) cls += " compare"; else if (step.type === "swap" && (i === step.i || i === step.minIdx)) cls += " compare"; } return `<div class="${cls}" style="height:${v * 10}px">${v}</div>`; }) .join(""); }; render(); document.getElementById("ss2-next").onclick = () => { if (idx >= steps.length - 1) return; idx++; const step = steps[idx]; render(); if (step.type === "compare") { out.textContent = `checking arr[${step.j}] -> current minimum is arr[${step.minIdx}]`; } else if (step.type === "swap") { out.textContent = step.minIdx !== step.i ? `swap arr[${step.i}] and arr[${step.minIdx}]` : `arr[${step.i}] is already the minimum -> no swap`; } else { out.textContent = "Sorted! ✅"; } }; document.getElementById("ss2-reset").onclick = () => { idx = -1; render(); out.textContent = 'Click "Next step" to scan for the minimum'; };}
function selectionSort(arr) { const result = [...arr] for (let i = 0; i < result.length - 1; i++) { let minIndex = i for (let j = i + 1; j < result.length; j++) { if (result[j] < result[minIndex]) minIndex = j } if (minIndex !== i) { ;[result[i], result[minIndex]] = [result[minIndex], result[i]] } } return result}selectionSort([6, 2, 9, 1, 5]) // [1, 2, 5, 6, 9]
07. Insertion Sort — Step by Step
Insertion sort grows a sorted section at the front, one item at a time. It lifts the next item out (the “hole”), then shifts bigger items right until it finds where the lifted item belongs.
<div class="hold" id="is-hold"></div><div class="bars" id="is-bars"></div><div class="btns"> <button class="btn" id="is-next">Next step</button> <button class="btn" id="is-reset">Reset</button></div><div class="out" id="is-out">Click "Next step" to lift out the second item</div>
const holdEl = document.getElementById("is-hold");const barsEl = document.getElementById("is-bars");const out = document.getElementById("is-out");if (holdEl && barsEl && out) { const initial = [7, 4, 9, 2, 6]; const n = initial.length; const buildSteps = (input) => { const arr = [...input]; const steps = []; for (let i = 1; i < n; i++) { const current = arr[i]; let hole = i; arr[hole] = null; while (hole > 0 && arr[hole - 1] > current) { steps.push({ type: "compare", i, hole, current, neighbor: hole - 1, snapshot: [...arr] }); arr[hole] = arr[hole - 1]; arr[hole - 1] = null; hole--; steps.push({ type: "shift", i, hole, current, snapshot: [...arr] }); } if (hole > 0) { steps.push({ type: "compare", i, hole, current, neighbor: hole - 1, stop: true, snapshot: [...arr] }); } arr[hole] = current; steps.push({ type: "place", i, hole, current, snapshot: [...arr] }); } steps.push({ type: "done", i: n, snapshot: [...arr] }); return steps; }; const steps = buildSteps(initial); let idx = -1; const render = () => { const snap = idx < 0 ? initial : steps[idx].snapshot; const step = idx < 0 ? null : steps[idx]; holdEl.textContent = step && step.type !== "done" ? `holding: ${step.current}` : ""; barsEl.innerHTML = snap .map((v, i) => { if (v === null) return `<div class="bar hole" style="height:20px"></div>`; let cls = "bar"; if (step) { if (step.type === "done") cls += " sorted"; else if (step.type === "compare" && i === step.neighbor) cls += " compare"; else if (i < step.i) cls += " placed"; } return `<div class="${cls}" style="height:${v * 10}px">${v}</div>`; }) .join(""); }; render(); document.getElementById("is-next").onclick = () => { if (idx >= steps.length - 1) return; idx++; const step = steps[idx]; render(); if (step.type === "compare") { const neighborVal = step.snapshot[step.neighbor]; out.textContent = step.stop ? `arr[${step.neighbor}] = ${neighborVal} <= ${step.current} -> stop, insert here` : `arr[${step.neighbor}] = ${neighborVal} > ${step.current} -> shift right`; } else if (step.type === "shift") { out.textContent = `shifted right -> hole now at index ${step.hole}`; } else if (step.type === "place") { out.textContent = `place ${step.current} at index ${step.hole}`; } else { out.textContent = "Sorted! ✅"; } }; document.getElementById("is-reset").onclick = () => { idx = -1; render(); out.textContent = 'Click "Next step" to lift out the second item'; };}
function insertionSort(arr) { const result = [...arr] for (let i = 1; i < result.length; i++) { const current = result[i] let j = i - 1 while (j >= 0 && result[j] > current) { result[j + 1] = result[j] // shift bigger item right j-- } result[j + 1] = current // drop current into the gap } return result}insertionSort([7, 4, 9, 2, 6]) // [2, 4, 6, 7, 9]
08. Merge Sort — Divide & Conquer
Merge sort splits the array in half recursively until every piece has a single item (already “sorted” on its own), then merges pairs of sorted pieces back together. The clever part is the merge — try it below with two halves that are already sorted.
<div class="merge-row"> <div class="merge-col"> <div class="merge-label">left</div> <div class="chips" id="ms-left"></div> </div> <div class="merge-col"> <div class="merge-label">right</div> <div class="chips" id="ms-right"></div> </div></div><div class="merge-label">result</div><div class="chips" id="ms-result"></div><div class="btns"> <button class="btn" id="ms-next">Next step</button> <button class="btn" id="ms-reset">Reset</button></div><div class="out" id="ms-out">Click "Next step" to compare the heads of each half</div>