ST
stevenvachon/react-splitting
A re-implementation of splitting.js (a text segmenter for animation) for React supporting SSR/SSG.
react-splitting

An (incomplete) re-implementation of splitting.js (a text segmenter for animation) for React supporting SSR/SSG.
This is a re-implementation because the original works with real DOM nodes. Converting ReactNodes to such then back again might preserve most--if not all--attributes, but will definitely lose all React event handlers.
Warning
- Only "chars" and "words" are supported for the
byproperty. <script>and<style>elements are property ignored.- The
keyoption was renamed tocssKeyto avoid a conflict with React's ownkeyproperty.- It is properly prefixed.
Note
- This library comes in two variants: one with "meta" and one without. The "meta" variant is a drop-in replacement for the original library as it replicates its CSS classes, CSS variables,
data-*attributes and some quirky whitespace handling. - Each variant can be used as a component--which offers nothing additional--or as a function--which adds segment counts and access to segment nodes before they're rendered.
Consumer Usage
Installation
npm install react-splitting<Splitting /> / splitting()
Lightweight and completely customizable.
import { Segmentation, Splitting } from 'react-splitting';
export default () => (
<>
<p>
<Splitting by={Segmentation.WORDS}>
Text <strong>split</strong> by <em>words</em>.
</Splitting>
</p>
<p>
<Splitting by={Segmentation.CHARS}>
Text <strong>split</strong> by <em>characters</em>.
</Splitting>
</p>
With more customization:
<p>
<Splitting
by={Segmentation.WORDS}
wordProps={i => ({ className: 'word', style: { '--word-index': i } })}
>
Text <strong>split</strong> by <em>words</em>.
</Splitting>
</p>
<p>
<Splitting
by={Segmentation.CHARS}
charProps={i => ({ className: 'char', style: { '--char-index': i } })}
wordProps={i => ({ className: 'word', style: { '--word-index': i } })}
>
Text <strong>split</strong> by <em>characters</em>.
</Splitting>
</p>
</>
);import { Segmentation, splitting } from 'react-splitting';
export default () => {
const { charCount, segments, wordCount } = splitting(
<>
Text <strong>split</strong> by <em>words</em>.
</>,
{
by: Segmentation.WORDS,
charProps: i => ({ className: 'char', style: { '--char-index': i } }),
wordProps: i => ({ className: 'word', style: { '--word-index': i } }),
}
);
return <p>{segments}</p>;
};<SplittingWithMeta /> / splittingWithMeta()
Drop-in replacement.
import { SplittingWithMeta } from 'react-splitting/with-meta';
export default () => (
<SplittingWithMeta as="div">
Text with <strong>added metadata</strong>, split by <em>characters</em>.
</SplittingWithMeta>
);import { splittingWithMeta } from 'react-splitting/with-meta';
export default () => {
const { charCount, container, wordCount } = splittingWithMeta(
<>
Text with <strong>added metadata</strong>, split by <em>characters</em>.
</>,
{ as: 'div' }
);
return container;
};Development Usage
Production Build
npm run buildTesting
The test suite can perform a single run:
npm test… or indefinitely as files are changed:
npm run test:watchTo Do
- Test with languages that don't use normal whitespace delimiters, such as Japanese, I think. Check out
Intl.Segmenter's "word"granularity. - Probably add ESLint.
- Remove tsc-alias and use
rewriteRelativeImportExtensionswithallowImportingTsExtensionswhen possible.
On this page
Languages
TypeScript99.4%JavaScript0.6%
Contributors
MIT License
Created November 16, 2025
Updated March 10, 2026