JavaScript Intl.Segmenter divides text into locale-aware graphemes, words, or sentences. It handles boundaries that simple string splitting often misses, including emoji sequences, combining marks, and languages that do not separate every word with a space.
You can use it for character counters, word selection, reading tools, search interfaces, and text editors without maintaining language-specific regular expressions.
Why Text Segmentation Matters
A JavaScript string stores UTF-16 code units. One visible character may contain multiple code units or Unicode code points. For example, a flag, family emoji, or accented letter can be split incorrectly by indexing or spreading a string.
- Grapheme represents a user-perceived character.
- Word finds locale-aware word boundaries.
- Sentence finds likely sentence boundaries.
Note: Segmentation follows locale data and Unicode rules. It identifies useful boundaries, but it does not understand the meaning of the text.
Create an Intl.Segmenter
Pass a locale and a granularity option to the constructor. The default granularity is grapheme.
Example:
// Create a segmenter for English word boundaries
const segmenter = new Intl.Segmenter("en-US", {
granularity: "word"
});
const segments = segmenter.segment("Asha learns JavaScript.");
console.log([...segments]);
The segment() method returns an iterable Segments object. Each entry contains the segment text, its UTF-16 index, the original input, and—at word granularity—an isWordLike value.
Count Visible Characters
Use grapheme segmentation when the interface must count what users see rather than code units.
Example:
const text = "Hi café!";
// Split the string into user-perceived characters
const graphemes = [
...new Intl.Segmenter("en", { granularity: "grapheme" })
.segment(text)
];
console.log(text.length);
console.log(graphemes.length);
console.log(graphemes.map(item => item.segment));
This is useful for input limits and cursor-related tools. The returned index still refers to the original string's UTF-16 positions.
Find Words in Locale-Aware Text
Splitting on spaces does not work reliably for punctuation or languages such as Chinese, Japanese, and Thai. Word segmentation supplies isWordLike so you can exclude spaces and punctuation.
Example:
const text = "Riya writes clean, readable code.";
const wordSegmenter = new Intl.Segmenter("en", {
granularity: "word"
});
// Keep only segments that behave like words
const words = [...wordSegmenter.segment(text)]
.filter(item => item.isWordLike)
.map(item => item.segment);
console.log(words);
console.log("Word count: " + words.length);
The exact result can vary with the requested locale and the implementation's current locale data. Choose the locale that best matches the content.
Segment Languages Without Spaces
A locale-aware segmenter can find useful word boundaries even when spaces are not the primary separator.
Example:
const japanese = "東京でプログラミングを学びます";
const segmenter = new Intl.Segmenter("ja-JP", {
granularity: "word"
});
// Display word-like Japanese segments
for (const item of segmenter.segment(japanese)) {
if (item.isWordLike) {
console.log(item.segment, item.index);
}
}
Split Text into Sentences
Sentence granularity uses locale-sensitive punctuation rules and keeps the original text in each segment.
Example:
const article = "Sam finished the report. Priya reviewed it! Is it ready?";
const segmenter = new Intl.Segmenter("en-GB", {
granularity: "sentence"
});
// Trim only for display; segmentation preserves original spacing
const sentences = [...segmenter.segment(article)]
.map(item => item.segment.trim());
console.log(sentences);
Sentence boundaries are educated text-based decisions. Abbreviations and specialized writing may require additional application rules.
Get the Segment at an Index
The returned Segments object provides containing(index). It finds the segment containing a UTF-16 index, which is helpful for selection and editor tools.
Example:
const text = "Learn JavaScript today";
const segments = new Intl.Segmenter("en", {
granularity: "word"
}).segment(text);
// Index 8 falls inside "JavaScript"
const current = segments.containing(8);
console.log(current.segment);
console.log(current.index);
console.log(current.isWordLike);
If the index is outside the string, containing() returns undefined.
Inspect Resolved Options and Locale Support
Use resolvedOptions() to check the locale and granularity selected by the runtime. The static supportedLocalesOf() method identifies requested locales that do not need default-locale fallback.
const segmenter = new Intl.Segmenter(["hi-IN", "en-IN"], {
localeMatcher: "best fit",
granularity: "word"
});
// Inspect the chosen configuration
console.log(segmenter.resolvedOptions());
// Check locale support in this environment
console.log(Intl.Segmenter.supportedLocalesOf([
"en-IN", "hi-IN", "ja-JP"
]));
Current browsers broadly support Intl.Segmenter, but older environments may not. Test for the constructor before depending on it in a compatibility-sensitive application.
Complete Intl.Segmenter Example
This runnable example counts visible characters and word-like segments from user input.
Run this example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Intl.Segmenter Example</title>
</head>
<body>
<label for="message">Enter text:</label>
<textarea id="message">Asha learns JavaScript smoothly</textarea>
<button id="analyze" type="button">Analyze</button>
<p id="result"></p>
<script>
// Analyze visible characters and word-like segments
document.querySelector("#analyze").addEventListener("click", () => {
const text = document.querySelector("#message").value;
const graphemes = new Intl.Segmenter("en", {
granularity: "grapheme"
});
const words = new Intl.Segmenter("en", {
granularity: "word"
});
const characterCount = [...graphemes.segment(text)].length;
const wordCount = [...words.segment(text)]
.filter(item => item.isWordLike).length;
document.querySelector("#result").textContent =
"Visible characters: " + characterCount + "; Words: " + wordCount;
});
</script>
</body>
</html>
Intl.Segmenter Granularity Values
| Value | Use | Extra result field |
|---|---|---|
| grapheme | User-perceived characters | None |
| word | Locale-aware word boundaries | isWordLike |
| sentence | Likely sentence boundaries | None |
Common Intl.Segmenter Mistakes
- Using string length as a visible-character count.
- Using spaces as universal word boundaries.
- Counting punctuation without checking
isWordLike. - Treating returned indexes as grapheme numbers instead of UTF-16 indexes.
- Assuming segmentation performs translation, stemming, or grammar analysis.
- Ignoring older-browser compatibility and locale differences.
Best Practices
- Create and reuse a segmenter when processing many strings with the same locale and granularity.
- Use the content's locale instead of the interface locale when they differ.
- Preserve returned indexes when mapping segments back to the original text.
- Test multilingual, emoji, combining-mark, and punctuation-heavy input.
- Add application-specific rules when generic boundaries are insufficient.
Conclusion
Intl.Segmenter gives JavaScript a standard way to find locale-aware grapheme, word, and sentence boundaries. Choose the correct granularity, filter word results with isWordLike, use containing() for index-based tools, and test the languages and Unicode text your application accepts.