Uppercase the first character and glue the rest back on: str.charAt(0).toUpperCase() + str.slice(1). It returns a new string, leaves the rest of the text as it was, and turns an empty string into "" instead of throwing.
JavaScript has no built-in capitalize() or ucfirst(), and strings are immutable, so every approach builds a new string from two pieces: the first character, uppercased, and everything after it. The one-liner is easy. The details are where the bugs are: an empty string, capitalizing every word, emoji and other characters that take up two UTF-16 code units, and languages such as Turkish whose capital letters differ from the English ones. If the text is only for display on a web page, CSS text-transform: capitalize can do it without touching the string; this page is about changing the string itself. Every example runs on this page: hit Run, then edit the code and run it again.
1charAt(0).toUpperCase() + slice(1)Recommended
charAt(0) returns the first character, toUpperCase() uppercases it, and slice(1) returns everything from index 1 onward. Wrap it in a small function and you have capitalize(). Characters with no uppercase form, such as digits and punctuation, come back unchanged, so you don't need to check the first character first.
Output
Output: Hello world, JavaScript, 42 apples, "", Hello world. Only the first character changes, so the capital S in javaScript survives. The empty string works because "".charAt(0) and "".slice(1) both return "". If you also want the rest lowercased, add .toLowerCase() to the slice, as capitalizeOnly does, but that also turns acronyms like NASA into Nasa. str.substring(1) works the same as str.slice(1) here. Avoid substr(): it is a legacy method that the spec only keeps for old code.
2str[0], a regex, or destructuring
You will also see three other versions. Bracket indexing str[0] is the most common one, and it gives the same result on any non-empty string. replace(/^./, …) uppercases whatever the regex matched at the start. Destructuring pulls the first character off the front. They differ on the empty string, which shows up whenever the input comes from a form field, a CSV cell or a split().
Output
The first three lines print Compile. The fourth prints "" undefined undefined: on an empty string charAt(0) returns "", but str[0] and str.at(0) return undefined, so calling .toUpperCase() on them fails with TypeError: Cannot read properties of undefined (reading 'toUpperCase'). The regex version prints "" because ^. has nothing to match, and the destructuring version is safe only because of the = "" default. If you prefer str[0], guard it: str && str[0].toUpperCase() + str.slice(1).
3Letters outside the BMP, emoji and surrogate pairs
A JavaScript string is a sequence of UTF-16 code units. Characters above U+FFFF, which include emoji and the letters of scripts such as Deseret, Osage and Adlam, take two code units each (a surrogate pair). charAt(), str[0], slice() and length all count code units, so charAt(0) returns half a character. Spreading the string ([...str]), codePointAt() and a regex with the u flag all work in whole code points instead.
Output
The first line prints 𐐨ello 6 5: five characters, six code units. charAt(0) is "\ud801", a lone high surrogate with no uppercase form, so the charAt version prints 𐐨ello unchanged. It doesn't corrupt anything, because the two halves are joined again, but it silently skips the capital. All three fixes print 𐐀ello. Emoji have no case, so 🚀 launch comes back intact from every version. The real risk with emoji is using the first character on its own, for an avatar initial say: charAt(0) gives you "\ud83d", half a rocket.
4Locale-aware: toLocaleUpperCase()
toUpperCase() applies Unicode's default case mapping, which is the same in every language. A few languages disagree with it. Turkish and Azerbaijani have a dotted i / İ pair and a dotless ı / I pair, so the capital of i is İ, not I. toLocaleUpperCase(locale) applies those rules when you pass it the language tag.
Output
Output: Istanbul, then İstanbul with the Turkish rules, then İzmir Izmir for the same word in Turkish and English. Lowercasing has the mirror problem: IRMAK becomes irmak by default but ırmak in Turkish. Always pass the locale explicitly. With no argument, toLocaleUpperCase() uses the runtime's default locale, which differs between machines, servers and browsers. The last line, SS 1 2, is a reminder that uppercasing can change a string's length: German ß has no single-character capital in the default mapping, so it becomes SS.
5Which should you use?
| Method | Empty string | Outside the BMP | Best for |
|---|---|---|---|
| str.charAt(0).toUpperCase() + str.slice(1) | Returns "" | Skips the capital | Almost everything |
| str[0].toUpperCase() + str.slice(1) | TypeError | Skips the capital | Input known to be non-empty |
| str.replace(/^./u, (c) => c.toUpperCase()) | Returns "" | Correct with the u flag | One expression, code-point safe |
| [first = "", ...rest] destructuring | Returns "" (needs the default) | Correct | A reusable, Unicode-safe helper |
| str.charAt(0).toLocaleUpperCase(locale) + str.slice(1) | Returns "" | Skips the capital | Turkish, Azerbaijani and other locale rules |
6Common variation: capitalize every word
To capitalize each word, apply the same function to every word. split(" ") plus map() plus join(" ") is the clearest version. A regex that uppercases the first non-space character after the start or after any whitespace handles tabs and newlines as well. The regex you will find most often, /\b\w/g, looks similar but breaks on real text.
Output
Output: The Quick Brown Fox, then Keep The Spacing with the extra spaces kept. split(" ") produces empty strings between repeated spaces, and charAt(0) handles them where str[0] would throw. The regex version prints "Tabs\tAnd\nNewlines Too". The \b\w version prints Don'T Lose Your éLan: \w only matches ASCII letters, digits and underscores, so there is a word boundary after the apostrophe and another between é and l. The whitespace regex gets it right: Don't Lose Your Élan. Lowercase the input first if it might arrive in capitals. Headline-style title case, which leaves words like "the" and "of" in lowercase, needs a list of those words on top of this.
Frequently asked questions
Does JavaScript have a built-in capitalize or ucfirst function?
No. There is no String.prototype.capitalize() and no equivalent of PHP’s ucfirst(), so you write the one-liner str.charAt(0).toUpperCase() + str.slice(1), usually in a small helper function. You can add a method to String.prototype, but it is discouraged: it can clash with another library or with a method a future version of JavaScript adds.
How do I capitalize the first letter and make the rest lowercase?
Lowercase the slice as well: str.charAt(0).toUpperCase() + str.slice(1).toLowerCase() turns "hELLO wORLD" into "Hello world". Only do this when you really want it, because it also turns acronyms and names like "NASA" or "McDonald" into "Nasa" and "Mcdonald".
Why does str[0].toUpperCase() throw on an empty string?
Because ""[0] is undefined, and undefined has no methods, so you get TypeError: Cannot read properties of undefined (reading 'toUpperCase'). "".at(0) is also undefined. "".charAt(0) returns an empty string instead, which is why the charAt version works on empty input without a check.
Why is the first letter not capitalized for some characters?
If the first character is above U+FFFF, it is stored as two UTF-16 code units, and charAt(0) or str[0] returns only the first half, which has no uppercase form. Work in code points instead: const [first = "", ...rest] = str; first.toUpperCase() + rest.join(""), or str.replace(/^./u, (c) => c.toUpperCase()). The u flag is what makes the dot match a whole code point.
Should I use toUpperCase() or toLocaleUpperCase()?
Use toUpperCase() for identifiers, keys and anything that must behave the same everywhere. Use toLocaleUpperCase(locale) with an explicit language tag when you capitalize text shown to people in a language with its own rules: in Turkish, "istanbul" capitalizes to "İstanbul", not "Istanbul". Without an argument it uses the runtime’s default locale, which varies between machines.
Can I use CSS text-transform: capitalize instead?
For display on a web page, yes: text-transform: capitalize uppercases the first letter of each word when the text is rendered. It does not change the string, so the value you store, compare or send to a server is still lowercase. It capitalizes every word, not just the first, so for a sentence-style capital use JavaScript or the ::first-letter pseudo-element.
Run it yourself
Open any of these in the full JavaScript editor: tweak, run, and share.
JavaScript playground