Vize

use-segmenter

Split text into graphemes, words, or sentences with Intl.Segmenter.

Package @vizejs/composable/use-segmenter
Own the source vize lib pull composable:use-segmenter
Runtime exports useSegmenter
Gzip budget 2816 B

Minimal setup

Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).

vp install @vizejs/composable

Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.

import { useSegmenter } from "@vizejs/composable/use-segmenter";

Try it

Count characters in a status update

Count and truncate text by the characters a reader sees, so an emoji sequence counts as one.

Open the interactive example

What to observe: Ship it 🚀👩‍👩‍👧 counts 10 characters even though the family emoji is several code points. The preview truncates to ten characters without splitting an emoji.

Use granularity: "word" or "sentence" to segment differently. wordCount counts word-like segments only.

Compare the initial and interacted states
Count characters in a status update: initial state
Initial state
Count characters in a status update: state after the verified interactions
After the verified interactions

Copy the example

Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.

<script setup lang="ts">
import { ref } from "vue";
import { useSegmenter } from "@vizejs/composable/use-segmenter";

const text = ref("Ship it 🚀👩‍👩‍👧");
const { graphemeCount, wordCount, truncate } = useSegmenter(text, { granularity: "grapheme" });
</script>

<template>
  <div class="composable-example">
    <p>Count what a reader sees as characters, so emoji count once.</p>
    <label>
      Status update
      <input v-model="text" />
    </label>
    <output aria-live="polite">{{ graphemeCount }} characters · {{ wordCount }} words</output>
    <p>Preview: {{ truncate(10) }}</p>
  </div>
</template>

Runtime contract

Utility Category Stability SSR Hydration Cleanup Targets Host globals Uses
useSegmenter i18n experimental deterministic-fallback caller-managed none web, server, worker, native, desktop, terminal Intl, window useLocale

API

useSegmenter

Split text into graphemes, words, or sentences with Intl.Segmenter. Counts reflect what users perceive: "👨‍👩‍👧" is one grapheme, and word counts skip spaces and punctuation while handling languages without spaces (Japanese, Thai) through the locale. truncate shortens text without splitting clusters. Derived state only; deterministic during server rendering when the locale is explicit.

function useSegmenter( text: MaybeRefOrGetter<string>, options: MaybeRefOrGetter<UseSegmenterOptions> = {}, ): SegmenterControls
const { graphemeCount, truncate } = useSegmenter(bio, { locale: "en" });
const remaining = computed(() => 160 - graphemeCount.value);

Types

TextSegment

One segment of the text.

Member Type Description
segment string Segment text.
index number UTF-16 code-unit offset of the segment in the source text.
isWordLike boolean Word granularity: whether the segment is a word (not spaces or punctuation).

UseSegmenterOptions

Options for useSegmenter.

Member Type Description
granularity? SegmenterGranularity Segmentation unit exposed through segments and count.
locale? string | Intl.Locale Locale whose segmentation rules are used (word boundaries in Japanese or Thai depend on it). Pass it explicitly for hydration-stable output.

SegmenterControls

Reactive segmentation returned by useSegmenter.

Member Type Description
locale ComputedRef<string> Canonical locale in use.
segments ComputedRef<readonly TextSegment[]> Segments at the configured granularity.
count ComputedRef<number> Number of segments at the configured granularity.
graphemeCount ComputedRef<number> User-perceived characters (grapheme clusters), independent of granularity.
wordCount ComputedRef<number> Word-like segments, independent of granularity.
truncate (maxGraphemes: number, ellipsis?: string) => string Truncate the text to at most maxGraphemes user-perceived characters, never splitting an emoji or combining sequence.