Truncate Text By Grapheme

Shorten UI text by grapheme clusters so emoji and combining marks stay intact, with an ellipsis budget included.

JavascriptData Integrity

Code

snippet
const segmenter = typeof Intl.Segmenter === "function"
  ? new Intl.Segmenter(undefined, { granularity: "grapheme" })
  : null;

export function truncateGraphemes(text, maxGraphemes, ellipsis = "\u2026") {
  if (!Number.isInteger(maxGraphemes) || maxGraphemes < 0) {
    throw new RangeError("maxGraphemes must be a non-negative integer");
  }
  const value = String(text);
  const graphemes = segmenter
    ? [...segmenter.segment(value)].map((part) => part.segment)
    : Array.from(value);
  if (graphemes.length <= maxGraphemes) return value;
  if (maxGraphemes === 0) return "";
  const suffix = ellipsis ? ellipsis : "";
  const budget = Math.max(0, maxGraphemes - 1);
  return graphemes.slice(0, budget).join("") + suffix;
}

export function truncateMiddle(text, maxGraphemes, marker = "\u2026") {
  const value = String(text);
  const graphemes = segmenter
    ? [...segmenter.segment(value)].map((part) => part.segment)
    : Array.from(value);
  if (graphemes.length <= maxGraphemes) return value;
  if (maxGraphemes <= 1) return marker;
  const keep = maxGraphemes - 1;
  const head = Math.ceil(keep / 2);
  const tail = Math.floor(keep / 2);
  return graphemes.slice(0, head).join("") + marker + graphemes.slice(-tail).join("");
}