Skip to main content

Overview

The core splitText() function provides framework-agnostic text splitting with automatic kerning compensation. Use it with Motion, GSAP, CSS animations, or any animation library.
import { splitText } from "griffo";
Bundle size: 7.11 kB (minified + brotli)

Basic Usage

import { splitText } from "griffo";
import { animate, stagger } from "motion";

const { chars } = splitText(document.querySelector("h1"), { type: "chars" });
animate(chars, { opacity: [0, 1], y: [20, 0] }, { delay: stagger(0.02) });

Split Types

Combine multiple split types with comma-separated values:
const { chars } = splitText(element, { type: "chars" });
// Returns: { chars: HTMLSpanElement[], words: [], lines: [] }
When splitting by chars, word wrappers are created internally for proper spacing even if type: "chars" is specified.

Masking for Reveal Animations

Wrap elements in overflow containers for clip-based reveals:
const { lines } = splitText(element, {
  type: "lines",
  mask: "lines",
});

animate(lines, { y: ["100%", "0%"] }, { delay: stagger(0.1) });
Masking wraps each element in a <span> with overflow: clip for clean slide-in/out animations.

Auto Re-split on Resize

Automatically re-split text when the container resizes:
const result = splitText(element, {
  type: "words,lines",
  autoSplit: true,
  onResplit: ({ words, lines }) => {
    // Re-animate after resize
    animate(words, { opacity: [0, 1] }, { delay: stagger(0.03) });
  },
});
autoSplit requires the element to have a parent in the DOM. It observes the parent’s width and triggers a full re-split when changed.

Debouncing

Control the debounce delay for resize events:
splitText(element, {
  autoSplit: true,
  resplitDebounceMs: 200, // Default: 100ms
  onResplit: ({ words }) => {
    console.log("Re-split triggered");
  },
});

Revert and Cleanup

Restore the original HTML and cleanup observers:
const { chars, revert } = splitText(element, { type: "chars" });

animate(chars, { opacity: [0, 1] }).finished.then(() => {
  revert(); // Restores original HTML
});

Auto-revert on Complete

splitText(element, {
  type: "words",
  revertOnComplete: true,
  onSplit: ({ words }) => {
    return animate(words, { opacity: [0, 1] }); // Auto-reverts when finished
  },
});
revertOnComplete works with Motion animations (.finished), GSAP timelines (.then()), and raw Promises.

Custom Classes and Indexes

const { chars, words, lines } = splitText(element, {
  type: "chars,words,lines",
  charClass: "my-char",
  wordClass: "my-word",
  lineClass: "my-line",
  propIndex: true, // Adds CSS custom properties
});

CSS Custom Properties

When propIndex: true, each element gets:
/* Character span */
.my-char {
  --char-index: 0;
}

/* Word span */
.my-word {
  --word-index: 0;
}

/* Line span */
.my-line {
  --line-index: 0;
}
Use in CSS animations:
@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
}

.my-char {
  animation: fadeIn 0.5s calc(var(--char-index) * 0.02s) both;
}

Initial Styles

Apply styles immediately after split:
splitText(element, {
  type: "words",
  initialStyles: {
    words: {
      opacity: 0,
      transform: "translateY(20px)",
    },
  },
  onSplit: ({ words }) => {
    animate(words, { opacity: 1, y: 0 }, { delay: stagger(0.05) });
  },
});

Function-based Styles

splitText(element, {
  type: "chars",
  initialStyles: {
    chars: (el, index) => ({
      opacity: 0,
      transform: `translateY(${20 + index * 5}px)`,
    }),
  },
});

Font Loading

Critical: Always wait for fonts before splitting to ensure accurate measurements.
// Recommended: Wait for fonts
document.fonts.ready.then(() => {
  const { words } = splitText(element, { type: "words" });
  animate(words, { opacity: [0, 1] });
});
React and Motion components handle this automatically via waitForFonts prop (enabled by default).

Advanced: Lifecycle Callbacks

const result = splitText(element, {
  type: "chars,words,lines",
  onSplit: ({ chars, words, lines }) => {
    // Called immediately after split
    console.log(`Split ${chars.length} chars into ${lines.length} lines`);

    // Return animation for revertOnComplete support
    return animate(chars, { opacity: [0, 1] });
  },
  autoSplit: true,
  onResplit: ({ chars, lines }) => {
    // Called when autoSplit triggers
    console.log(`Re-split into ${lines.length} lines`);
  },
  revertOnComplete: true,
});

Full API Reference

element
HTMLElement
required
The HTML element containing text to split
options.type
string
default:"chars,words,lines"
Split types: "chars", "words", "lines", or comma-separated combinations
options.mask
'lines' | 'words' | 'chars'
Wrap elements in overflow containers for reveal animations
options.autoSplit
boolean
default:false
Automatically re-split on container resize
options.resplitDebounceMs
number
default:100
Debounce delay for autoSplit in milliseconds
options.revertOnComplete
boolean
default:false
Auto-revert when onSplit animation completes
options.propIndex
boolean
default:false
Add CSS custom properties (--char-index, --word-index, --line-index)
options.disableKerning
boolean
default:false
Skip kerning compensation (see Kerning Guide)
options.onSplit
function
Callback after split. Return animation for revertOnComplete.
options.onResplit
function
Callback when autoSplit triggers
options.initialStyles
object
Apply styles after split. Supports static objects or functions.
options.charClass
string
default:"split-char"
Class name for character spans
options.wordClass
string
default:"split-word"
Class name for word spans
options.lineClass
string
default:"split-line"
Class name for line spans

Return Value

interface SplitTextResult {
  chars: HTMLSpanElement[];
  words: HTMLSpanElement[];
  lines: HTMLSpanElement[];
  revert: () => void;
}

React

Use SplitText with React lifecycle

Motion

Declarative animations with Motion

Kerning

How kerning compensation works

Performance

Optimization tips

Build docs developers (and LLMs) love