String.prototype.codePointAt()
Returns the full Unicode code point at an index, keeping surrogate pairs such as emoji intact.
codePointAt(index)- Added in JavaScript ECMAScript 2015
Parameters
| Parameter | Type | Description |
|---|---|---|
$index | number | Zero-based index of the character whose code point is returned. Converted to an integer; undefined becomes 0. |
Return value
number | undefinedA non-negative integer: the code point at the given index, or undefined when the index is outside 0 – str.length - 1.
codePointAt() is the Unicode-correct counterpart to charCodeAt(). When the code unit at index is a leading surrogate (U+D800–U+DBFF) and a trailing surrogate follows, it combines both and returns the real code point — up to 0x10FFFF. In every other case it returns the same value charCodeAt() would.
Index arithmetic is the catch
The index is still measured in code units. Reading a code point at index 0 of an emoji does not make index 1 the next character — index 1 is the trailing surrogate, and asking for it returns that lone surrogate value rather than undefined. A manual loop must advance by cp > 0xFFFF ? 2 : 1. Iterating with for...of or spreading the string does that stepping for you and is almost always the better choice.
Where you actually need it
Reach for it when a code point number is the goal: building a U+ label, checking whether a character sits in an emoji or CJK block, or feeding String.fromCodePoint() to round-trip. Note that a code point is still not a user-visible character — flags, skin tones and ZWJ sequences are several code points glued together, and only Intl.Segmenter counts those as one.
Example
When to use it
- Print a character's U+XXXX identifier in a debugging tool
- Test whether input contains astral characters before storing it
- Round-trip a character through String.fromCodePoint()
- Step through text one real code point at a time in a lexer
Frequently asked questions
What is the difference between codePointAt() and charCodeAt()?
codePointAt() combines a surrogate pair into the real code point (up to 0x10FFFF), while charCodeAt() only ever returns a single 16-bit code unit and hands back half of an emoji.
How do I get the Unicode code point of an emoji?
Use emoji.codePointAt(0), then .toString(16) for the hex form used in U+1F600 style labels. Spread or iterate first if the emoji is not at the start of the string.
Why does codePointAt(1) return a strange number for a 2-character string?
Index 1 lands on the trailing surrogate of a pair, and the method returns that surrogate value verbatim. Advance by 2 after a code point above 0xFFFF, or iterate with for...of.
More examples
Labelling every code point
for...of walks code points, so each ch is a complete character and codePointAt(0) on it always gives the full value. The two length readings show the code-unit / code-point gap.
const text = "a\u{1F600}b";
for (const ch of text) {
const cp = ch.codePointAt(0);
console.log(ch, "U+" + cp.toString(16).toUpperCase().padStart(4, "0"));
}
// a U+0061
// 😀 U+1F600
// b U+0062
console.log(text.length); // 4 code units
console.log([...text].length); // 3 code pointsDetecting astral characters
Anything above 0xFFFF needs a surrogate pair, which is the practical test for "will a code-unit API mangle this". The family emoji shows the remaining gap: 5 code points that render as one glyph.
const hasAstral = (s) => [...s].some((ch) => ch.codePointAt(0) > 0xffff);
console.log(hasAstral("plain ascii")); // false
console.log(hasAstral("café")); // false — é is U+00E9
console.log(hasAstral("ship it \u{1F680}")); // true
// A code point still is not a visible character:
const family = "\u{1F468}\u{1F469}\u{1F467}";
console.log(family.length, [...family].length); // 8 5
Discussion