cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Comparing & sorting text

Compare strings by code units, sort human text with localeCompare and Intl.Collator, handle locale-aware case conversion, and build case-insensitive search that respects accents.

By the end, you can
  • 01
    Explain default orderPredict when code-unit comparison puts capitals or accents in surprising places.
  • 02
    Choose locale toolsUse localeCompare for one-off comparisons and reuse Intl.Collator for bigger sorts.
  • 03
    Search kindlyFold case and accents deliberately instead of assuming toLowerCase() solves every language.

Humans and code units want different things

JavaScript can compare any two strings immediately, but its fastest default answer is not a human dictionary. It compares the numbers inside the string: UTF-16 code units. You met those numbers in Unicode & string internals. They are perfect for a precise machine rule and surprising for names, titles, product lists, and search boxes.

This lesson is the bridge between simple Comparisons, array Sorting & copying safely, and the later Internationalization with Intl module. You will still write ordinary comparators, but the comparison itself will come from text-aware tools.

One-line definition

Text collation is the set of rules that decides whether one string should come before, after, or equal to another string for a particular language and purpose.

Real-life analogySorting names in a contact list

A machine can sort names by the codes behind their letters. Your phone sorts contacts in an order people expect for a chosen language. JavaScript can do either job.

In real life: The code behind each letter
In JavaScript: A character’s UTF-16 code unit
In real life: Sorting those codes
In JavaScript: Default <, >, and string sort()
In real life: Your phone’s contact order
In JavaScript: Calling localeCompare with a locale
In real life: Keeping one contact-list setting
In JavaScript: Reusing one Intl.Collator

Where the analogy stops: A phone chooses its own contact rules. JavaScript follows the locale and options you provide.

Default string comparison is code-unit comparison

STEP THROUGH

When both sides of < are strings, JavaScript compares the first code unit where they differ. The same default appears when Array.prototype.sort() sorts strings without a comparator.

The numbers behind a surprisePop out in the code editor (opens in a new tab)JavaScript
console.log("a".charCodeAt(0)); // 97console.log("Z".charCodeAt(0)); // 90 console.log("Zebra" < "apple"); // true

Code-unit order is not wrong. It is just a machine promise, not a language promise. It also explains why "10" < "9": the first code unit "1" comes before "9".

Code-unit sort or locale sort?
Step 0 of 3Ready
Your turn: follow the blue line

Switch the comparison method, predict the printed order, then step through the recorded run.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const sorted = [...words].sort();console.log(sorted.join(", "));
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Change line 2: which comparison method should sort use?

Changing the method starts a fresh replay. Predict the printed order before stepping.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Use default order for IDs, exact protocol strings, and places where you truly want code-unit order. For names and labels shown to users, choose a locale-aware comparison.

localeCompare asks for dictionary-like order

INTERACTIVE

Every string has localeCompare. It returns a negative number, zero, or a positive number: before, equal for this comparison, or after. That shape is exactly what sort comparators need.

One-off locale comparisonPop out in the code editor (opens in a new tab)JavaScript
"äpfel".localeCompare("zebra", "de"); // negative"äpfel".localeCompare("zebra", "sv"); // positive[...names].sort((a, b) => a.localeCompare(b, "de"));

The important habit is to pass an explicit locale such as "en", "de", "sv", or "tr". If you omit it, JavaScript uses the environment’s default locale. That can be useful for an app configured from the user’s language, but examples and tests should be explicit.

Ask different dictionaries
const words = ["zebra", "äpfel", "apfel", "åre", "öl"];const collator = new Intl.Collator(locale);const sorted = [...words].sort(collator.compare);
Sorted with en5 words
apfeläpfelåreölzebra

Sensitivity check: with base, a vs á is 0; with accent, it is -1.

Try it yourself
Locale:

English and German put these accented words near their base letters in this list. Change to sv to see a different alphabet order.

Locale data can vary at the edges, so this lesson asserts explicit locales with Node’s full ICU and keeps the browser display interactive after hydration.
Real-life analogySensitivity is a phone contact setting

Pick how closely your phone should compare contact names. For search, a, A, and á can count as equal. For spelling, the accent can matter.

In real life: Ignore case and accents
In JavaScript: sensitivity: "base"
In real life: Keep accent differences
In JavaScript: sensitivity: "accent"
In real life: Keep case differences
In JavaScript: sensitivity: "case" or variant

Where the analogy stops: A contact list also sorts names. JavaScript follows the locale and sensitivity you choose.

Intl.Collator is the reusable comparator

SORTER

localeCompare is convenient for one or two comparisons. For a big sort, create one Intl.Collator and reuse its compare method. That avoids re-explaining the same locale and options for every pair.

Common Intl.Collator options
OptionWhat it changesExample
sensitivity: "base"Ignore case and accents for many languagesa, A, and á compare equal in English
sensitivity: "accent"Ignore case, but keep accent differencesa and A match; a and á differ
sensitivity: "case"Ignore accents, but keep case differencesUseful only when case matters more than accents
sensitivity: "variant"Most precise common comparisonCase, accents, and variants can all matter
numeric: trueCompare digit runs as numbersitem9 sorts before item10
caseFirstAsk whether upper or lower case sorts firstupper, lower, or false
Code-unit order or locale order?
  • "Zebra" < "apple"
  • ["banana", "apple", "Cherry"].sort()
  • names.sort((a, b) => a.localeCompare(b, "de"))
  • names.sort(new Intl.Collator("sv").compare)
  • new Intl.Collator("en", { numeric: true })
  • "a".charCodeAt(0) > "Z".charCodeAt(0)
Try it yourself
0 of 6 correct

Sort each comparison into the rule it uses.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

numeric: true is the file-name option people notice first. Without it, item10 often sorts before item9 because 1 comes before 9. With it, digit runs compare as numbers.

Case conversion can be locale-aware too

INTERACTIVE

toUpperCase() and toLowerCase() are useful, but not every language treats letters like English. Locale-aware forms let you name the rules: toLocaleUpperCase(locale) and toLocaleLowerCase(locale).

Case changes depend on locale
Locale case examplesPop out in the code editor (opens in a new tab)JavaScript
"i".toLocaleUpperCase("tr"); // "İ""I".toLocaleLowerCase("tr"); // "ı""ß".toLocaleUpperCase("de"); // "SS"
Real resultsexplicit locales
Turkish uppercase of iİ
Turkish lowercase of Iı
German uppercase of ßSS
Try it yourself
Fixed examples

Turkish has dotted and dotless I, and German ß uppercases to SS in JavaScript. Locale-aware case methods let you name the rules you want.

These examples use explicit tr and de locales so the result is not guessed from the reader’s browser settings.

This matters most when you store or compare folded text. A Turkish user can reasonably expect dotted i and dotless ı behavior. A German user can reasonably expect ß to uppercase to SS in JavaScript. Do not invent your own case table.

Where you’ll use this

You will use text comparison anywhere users scan a list: contact names, countries, product titles, table columns, command palettes, and file names. The safest pattern is: keep the original string for display, build a comparison or search helper for the task, and name the locale/options explicitly.

Product list patternPop out in the code editor (opens in a new tab)JavaScript
const collator = new Intl.Collator(userLocale, {  sensitivity: "base",  numeric: true,}); const visibleProducts = products  .filter((product) => matchesSearch(product.name, query))  .sort((a, b) => collator.compare(a.name, b.name));
Performance note

Reuse one Intl.Collator for a big sort. Creating it once beside the sort is usually clearer and cheaper than calling localeCompare with the same options thousands of times.

Common misconceptions

  • “Alphabetical” is universal. Different languages place ä, å, and ö differently.
  • sort() knows my users. Plain sort uses code-unit string order unless you pass a comparator.
  • The sign from localeCompare is always -1 or 1. Only negative, zero, or positive is guaranteed.
  • Lowercasing both sides solves search forever. It misses accent and locale choices.
  • Equal for sorting means identical strings. With sensitivity: "base", different strings can compare as equal.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upPredict default sort

Run the code mentally before checking. Type the exact order printed by the default sort.

Starter codePop out in the code editor (opens in a new tab)JavaScript
const words = ["banana", "apple", "Cherry", "éclair"];
console.log(words.sort().join(", "));

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeSort names for German users

    Use German collation rules and keep the original array safe by sorting a copy.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const names = ["Özil", "Oden", "Änne", "Anna"];
    const collator = new Intl.Collator("de");
    console.log([...names].sort(collator.compare).join(", "));

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeNatural-sort file names

      Make the file names sort the way a file picker should: 1, 2, 10.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const files = ["file10", "file2", "file1"];
      const collator = new Intl.Collator("en", { numeric: true });
      console.log([...files].sort(collator.compare).join(", "));

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · ChallengeBuild an accent-insensitive filter

        Fill in the fold-and-filter strategy, then predict which displayed name matches zoe.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        function fold(value) {
          return value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
        }
        const names = ["Jose", "José", "Zoë"];
        console.log(names.filter((name) => fold(name).includes(fold("zoe"))).join(", "));

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeFix the case-insensitive comparison bug

          The bug lowercases both strings but still treats accents as different. Replace it with a collator equality check.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          // Bug: accents are treated as different.
          console.log("Résumé".toLowerCase() === "resume".toLowerCase());

          Answer, then press Check. Spacing and letter case don’t matter.

            Check your understanding

            7 QUESTIONS
            Comparing text quiz · 7 questionsScore: first tries count
            1. Question 1 of 7What does JavaScript’s < use when both values are strings?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does this print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log("Zebra" < "apple");

              Choose an answer to see the explanation.

            3. Question 3 of 7Which tool is best for sorting thousands of displayed names with the same rules?

              Choose an answer to see the explanation.

            4. Question 4 of 7What does natural sorting print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const c = new Intl.Collator("en", { numeric: true });
              console.log(["item10", "item9", "item1"].sort(c.compare).join(", "));

              Choose an answer to see the explanation.

            5. Question 5 of 7What does this print in Turkish?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log("i".toLocaleUpperCase("tr"));

              Choose an answer to see the explanation.

            6. Question 6 of 7For case- and accent-insensitive equality, which comparison is clearest?

              Choose an answer to see the explanation.

            7. Question 7 of 7What does the accent-insensitive fold print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const folded = "Résumé".normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase();
              console.log(folded);

              Choose an answer to see the explanation.

            Key takeaways

            • Default string comparison is UTF-16 code-unit comparison: fast, stable, and often alien to humans.
            • Use localeCompare for one-off locale-aware comparisons.
            • Use one Intl.Collator when sorting many items with the same locale and options.
            • Locale-aware case conversion matters for languages such as Turkish, and ß can expand to SS.
            • Case-insensitive search needs a policy for normalization, accents, and locale.

            Comparing text well means choosing the rule your user expects, not the rule JavaScript can apply fastest.

            Up next: Destructuring arrays.

            CompleteFrontend Clear concepts. Working examples.