String.prototype.isWellFormed() returns whether a string has any lone UTF-16 surrogates (same API as MDN String.prototype.isWellFormed()). Learn well-formed vs broken pairs, emoji that pass the check, guarding encodeURI(), pairing with toWellFormed(), five examples, and try-it labs.
01
Kind
Instance method
02
Returns
true / false
03
Parameters
None
04
Checks
Lone surrogates
05
Mutates?
No
06
Baseline
Widely available
Fundamentals
Introduction
JavaScript strings are stored as UTF-16. Characters above U+FFFF (including many emoji) need two code units called a surrogate pair: a high (leading) surrogate plus a low (trailing) one.
Sometimes data arrives with only one half of that pair — a lone surrogate. That string is ill-formed. It may still look odd in the console, but APIs like encodeURI() can throw a URIError when they see it.
💡
Beginner tip
Everyday text like "hello" and complete emoji like "😄" are well-formed. You mainly need isWellFormed() when text comes from binary buffers, cut-and-paste bugs, or other low-level sources.
isWellFormed() scans the string for unpaired surrogates. Engines can do this efficiently against the internal UTF-16 data — faster and clearer than a hand-written loop.
No parameters — just call str.isWellFormed().
Returns true when every surrogate is part of a valid pair (or none exist).
Returns false when any lone high or low surrogate is present.
Does not fix the string — use toWellFormed() when you need a repaired copy.
Foundation
📝 Syntax
General form of String.prototype.isWellFormed:
JavaScript
str.isWellFormed()
Parameters
None — this method does not accept arguments.
Return value
A boolean. Special cases:
Situation
Returns
Normal text (e.g. "abc", empty "")
true
Valid surrogate pair (e.g. emoji "😄")
true
Lone leading surrogate (e.g. "ab\uD800")
false
Lone trailing surrogate (e.g. "\uDFFFab")
false
Mixed text with any lone surrogate inside
false
Common patterns
JavaScript
"hello".isWellFormed(); // true
"\uD800".isWellFormed(); // false (lone high surrogate)
"😄".isWellFormed(); // true (valid pair)
if (!text.isWellFormed()) {
console.warn("Ill-formed UTF-16");
text = text.toWellFormed(); // replace lone surrogates with U+FFFD
}
Cheat Sheet
⚡ Quick Reference
Goal
Code
Check well-formed UTF-16
str.isWellFormed()
Guard encodeURI
if (str.isWellFormed()) encodeURI(str)
Repair lone surrogates
str.toWellFormed()
Reject bad input
if (!str.isWellFormed()) throw ...
Empty string
"".isWellFormed() → true
Valid emoji
"😀".isWellFormed() → true
Snapshot
🔍 At a Glance
Four facts to remember about String.isWellFormed().
Returns
boolean
true if no lone surrogates
Parameters
none
Empty call only
Emoji pairs
true
Complete pairs pass
Mutates
no
Strings stay immutable
Compare
📋 isWellFormed() vs toWellFormed()
isWellFormed()
toWellFormed()
Purpose
Detect lone surrogates
Replace them with U+FFFD
Result type
Boolean
New string
Original string
Unchanged
Unchanged (returns a copy)
Best for
Validate / branch / warn
Sanitize before encode or display
Typical combo
if (!s.isWellFormed()) ...
encodeURI(s.toWellFormed())
Hands-On
Examples Gallery
Examples follow MDN String.isWellFormed() patterns. Use View Output or Try It Yourself for each case.
📚 Getting Started
See true vs false for common cases.
Example 1 — Basic isWellFormed() Checks
MDN-style loop: lone surrogates fail; normal text and valid pairs pass.
length counts UTF-16 units, so a lone surrogate has length 1 and a complete emoji has length 2. Well-formedness is about pairing, not about length alone.
📈 Practical Patterns
Emoji that pass, encodeURI safety, and repairing text.
Example 3 — Everyday Text and Emoji Pass
Normal strings and complete emoji are well-formed — no special escaping needed.
JavaScript
console.log("".isWellFormed()); // true
console.log("CodeToFun".isWellFormed()); // true
console.log("你好".isWellFormed()); // true
console.log("😀🎉".isWellFormed()); // true
// Broken: cut the emoji in half by taking only the first unit
const broken = "😀".charAt(0);
console.log(broken.isWellFormed()); // false
console.log(broken.charCodeAt(0)); // 55357 (high surrogate)
charAt(0) on an emoji returns only the high surrogate — a classic way to create ill-formed text by accident. Prefer for...of or codePointAt(0) when working with emoji.
Example 4 — Avoid encodeURI() Errors
MDN pattern: test before encoding so you do not catch a URIError.
Walk the string’s internal code units from start to end.
Scan
2
Match surrogate pairs
A high unit must be followed by a low unit; a low unit must follow a high.
Pairs
3
Spot orphans
Any unpaired high or low surrogate means the string is ill-formed.
Detect
4
✅
Return true or false
true if every unit is fine; false if any lone surrogate exists.
Important
📝 Notes
Takes no parameters — always call isWellFormed() with empty parentheses.
Valid emoji and other supplementary characters use paired surrogates and return true.
Slicing or charAt in the middle of an emoji can create ill-formed strings.
This is not the same as Unicode normalization (normalize()) — that deals with composed vs decomposed forms.
Prefer the built-in method over a custom surrogate loop — engines optimize the check.
Baseline widely available since October 2023 — polyfill if you must support older runtimes.
Compatibility
Browser & Runtime Support
String.prototype.isWellFormed() is Baseline Widely available — supported across modern browsers since October 2023.
✓ Baseline · Widely available
String.isWellFormed()
Safe for current production browsers. Pair with toWellFormed() when you need to sanitize ill-formed text.
ModernWidely available
Google ChromeSupported · Desktop & Mobile
Full support
Mozilla FirefoxSupported · Desktop & Mobile
Full support
Apple SafariSupported · macOS & iOS
Full support
Microsoft EdgeSupported · Chromium
Full support
Internet ExplorerNo native support · Use a polyfill
Polyfill
OperaSupported · Modern versions
Full support
Samsung InternetSupported · Android
Full support
BunSupported · JavaScript runtime
Supported
DenoSupported · JavaScript runtime
Supported
Node.jsSupported · Server runtime
Supported
Android WebViewSupported · Modern WebView
Full support
isWellFormed()Excellent
Bottom line: Use String.isWellFormed() to detect lone UTF-16 surrogates before encodeURI or other strict APIs. Repair with toWellFormed() when you need a safe string.
Wrap Up
Conclusion
String.prototype.isWellFormed() returns true when a string has no lone UTF-16 surrogates, and false otherwise. Use it to validate text, avoid URIError from encodeURI, and decide when to call toWellFormed().
Call isWellFormed() before encodeURI on untrusted text
Use toWellFormed() when you need a repaired copy
Iterate emoji with for...of to avoid cutting pairs
Treat false as a signal to reject, warn, or sanitize
Prefer the built-in check over hand-rolled surrogate logic
❌ Don’t
Pass arguments — the method takes none
Assume every string from a buffer is well-formed
Use charAt / fixed-width slices on emoji without checking
Confuse this with normalize() (different problem)
Forget older environments may need a polyfill
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about String.isWellFormed()
Boolean check for lone UTF-16 surrogates — pair with toWellFormed() to repair.
5
Core concepts
📝01
Returns
true / false
API
🔀02
Detects
lone surrogates
UTF-16
😀03
Emoji
complete pairs pass
Unicode
🔗04
Guard
encodeURI safely
URI
🛠05
Repair
toWellFormed()
Sanitize
❓ Frequently Asked Questions
String.prototype.isWellFormed() returns true if the string has no lone UTF-16 surrogates, and false if it contains any unpaired high or low surrogate.
UTF-16 uses pairs of code units for characters above U+FFFF (like many emoji). A lone (orphan) surrogate is one half of that pair without its matching partner — for example "\uD800" alone.
No. Call it with empty parentheses: str.isWellFormed(). There is nothing to configure.
Before APIs that reject ill-formed strings (such as encodeURI()), when validating text from binary or network sources, or when you want to treat broken surrogate data differently from normal text.
isWellFormed() only checks and returns a boolean. toWellFormed() returns a new string where lone surrogates are replaced with the Unicode replacement character (U+FFFD).
No. Strings are immutable. isWellFormed() only reads and returns true or false.
Did you know?
Lone surrogates often appear when code treats strings as arrays of fixed-width units — for example "😀"[0] or str.slice(0, 1) on an emoji. Those operations return one UTF-16 unit, which is why isWellFormed() suddenly returns false.