Case normalization converts text to one consistent case, such as lowercase emails, uppercase state codes, or title case names, so values that mean the same thing compare as equal. Case folding is the stricter version used for comparison, which also maps characters such as the German ß to ss.
Why it matters when importing data
To a computer, Ana@Example.com and ana@example.com are different strings, so mixed case creates duplicate contacts, failed lookups, and unique checks that pass when they should not. Names typed in all caps or all lowercase also look careless when they appear in your product. Normalizing on import fixes both.
Normalizing Cases in JavaScript
Pick the case by what the field is for: lowercase for emails and usernames, uppercase for codes, title case for names you display. This title case function capitalizes after spaces and hyphens, and after the O' and D' prefixes so o'neil becomes O'Neil while macy's stays Macy's. The u flag makes it work for accented letters:
// Title case that capitalizes after spaces and hyphens, and after the O' and D'
// prefixes, so "o'neil" becomes "O'Neil" but "macy's" stays "Macy's".
const toTitleCase = (value) =>
value
.trim()
.toLowerCase()
.replace(
/(^|[\s-])(\p{L})/gu,
(match, separator, letter) => separator + letter.toUpperCase()
)
.replace(
/(^|[\s-])([OD])'(\p{L})/gu,
(match, separator, prefix, letter) =>
separator + prefix + "'" + letter.toUpperCase()
);
const rows = [
{ name: "mary-jane SMITH", email: "Mary.Smith@Example.COM", state: "ca" },
{ name: "o'neil, PAT", email: "PAT@example.com ", state: "Ny" },
{ name: "DAVID mcdonald", email: "d.mcdonald@example.com", state: "tx" },
{ name: "MACY'S buyer team", email: "Buyers@Macys.com", state: "OH" },
];
const results = rows.map((row) => ({
name: toTitleCase(row.name),
email: row.email.trim().toLowerCase(),
state: row.state.trim().toUpperCase(),
}));
console.table(results); Input
| name | state | |
|---|---|---|
| mary-jane SMITH | Mary.Smith@Example.COM | ca |
| o'neil, PAT | PAT@example.com | Ny |
| DAVID mcdonald | d.mcdonald@example.com | tx |
| MACY'S buyer team | Buyers@Macys.com | OH |
Output
| Name | State | |
|---|---|---|
| Mary-Jane Smith | mary.smith@example.com | CA |
| O'Neil, Pat | pat@example.com | NY |
| David Mcdonald | d.mcdonald@example.com | TX |
| Macy's Buyer Team | buyers@macys.com | OH |
Edge cases to handle
- Names that break title case.
McDonald,van der Berg, andDeShawndo not follow the rule, as the last row shows. Only title case names when the source is all caps or all lowercase, and let users correct exceptions. - Compare with folding, store with care. For matching,
a.localeCompare(b, undefined, { sensitivity: "base" }) === 0ignores case and accents. Store the user's version unless the field is an identifier such as an email. - Locale. Turkish has a dotted and dotless i, so
"I".toLowerCase()is wrong for Turkish text. UsetoLocaleLowerCase("tr")when the locale is known. - Trim first. A trailing space survives case conversion and still breaks equality. Trim before you normalize.
How Dromo handles normalizing cases
Dromo's unique_case_insensitive validator flags duplicates that differ only by case, so Ana@Example.com and ana@example.com are caught even before you normalize them. To change the stored value, a column hook can lowercase, uppercase, or title case an entire column before the review step, and the user can still edit individual cells.
Related terms
- Trimming Fields: Removing unwanted whitespace from the start and end of a value.
- Removing Duplicates: Finding rows that represent the same thing and keeping one.
- Finding Text Within a String: Locating a substring inside a value, and optionally replacing it.
Frequently asked questions
What is case normalization?
Case normalization converts text to a single consistent case, such as all lowercase, so that values that differ only by capitalization are treated as the same value when comparing, deduplicating, or searching.
Should emails be stored in lowercase?
In practice, yes. The domain part of an email address is case-insensitive, and almost every mail provider treats the local part as case-insensitive too, so lowercasing emails on import prevents duplicate accounts. The email standard (RFC 5321) technically allows a case-sensitive local part, so use the lowercased value as the matching key.