Documentation

Documentation

splitText

splitText is a tiny (+0.7kb) utility that makes it simple to create complex, beautiful split text animations with Motion.

Break down text into individual characters, words, and lines, to create staggered enter or scroll-driven text effects with just a few lines of code.

splitText is exclusive to Motion+ members. Motion+ is a one-time payment, lifetime membership that unlocks exclusive components, premium examples and access to a private Discord community.

Features

  • Animate anything: Split text into characters, words and lines to animate each independently.

  • Lightweight: Only adds 0.7kb to your project bundle.

  • Simple API: A clean API leaves your code maintainable.

  • Accessible: Correctly applies ARIA tags to leave your text readable for all users.

  • Flexible: Animate with Motion, CSS, or a library of your choice.

Install

First, add the Motion+ library to your project using your private token. You need to be a Motion+ member to generate a private token.

npm install https://api.motion.dev/registry\?package\=motion-plus\&version\=1.5.4\&token

Once installed, splitText can be imported via motion-plus:

import { splitText } from "motion-plus"

Usage

splitText accepts a CSS selector or an HTML Element. It replaces the element's text content with <span> tags that wrap individual characters, words, and (optionally) lines.

It returns an object containing chars, words, and lines as arrays of elements, so they can be animated right away with Motion's animate and stagger functions.

const { chars } = splitText("h1")

animate(
  chars,
  { opacity: [0, 1], y: [10, 0] },
  { duration: 1, delay: stagger(0.05) }
)

The returned arrays are regular elements so you're not limited to animating them with Motion. You could animate them with CSS, or another animation library of your choice. Or, you could attach gesture recognisers to each element individually, for instance with Motion's hover function.

const { words } = splitText("h1")

hover(words, (wordElement) => {
  // Hover logic
})

Techniques & troubleshooting

Enter animations

To perform enter animations, it might be necessary to set the container to visibility: hidden via CSS until we're ready to animate.

.container {
  visibility: hidden;
}
document.querySelector(".container").style.visibility = "visible"

const { words } = splitText(".container")
animate(words, { opacity: [0, 1] })

Otherwise we might see a flash of visible text until our JS has loaded.

Working with custom fonts

If you have custom fonts that download after splitText is executed, it can be that the text is split incorrectly because the dimensions of the text have changed.

To fix this, we can await the browser's document.fonts.ready promise:

document.fonts.ready.then(() => {
  const { words } = splitText(element)

  animate(
    words,
    { y: [-10, 10] },
    { delay: stagger(0.04) }
  )
})

Targeting with CSS

Each split component will receive split-char, split-word and split-line classes so you can select them with CSS. Each component additionally receives a data-index of its position within the overall character, word or line lists respectively.

.split-char[data-index=3] {
  color: red;
}

The provided classes are configurable with the charClass, wordClass and lineClass options.

splitText(element, { charClass: "my-char-class" })

splitText doesn't currently preserve existing tags within the text, so links and other styling spans will be removed.

It's possible to fix this by wrapping the text before/after the tag with its own span and splitting these individually:

<h2>
  <span class="before">Before</span>
  <a href="#">Link</a>
  <span class="after">After</span>
</h2>

<script>
  const chars = [
    ...splitText(".before").chars,
    ...splitText("a").chars,
    ...splitText(".after").chars,
  ]
</script>

SVG <text /> isn't working

<text /> elements are not supported.

text-align: justify is being lost

Splitting test in this way is incompatible with how browsers handle text-align: justify. You can implement something similar by adding styles for split-line:

.align-justify .split-line {
  display: flex;
  justify-content: space-between;
}

Options

splitBy

Default: " " (space)

The string to split the text by.

<p>My+custom+text</p>
splitText(paragraph, { splitBy: "+" })

Note: When splitting with a custom character, lines might start to wrap. Ensure the wrapper element is set to text-wrap: nowrap to keep text on a single line.

charClass

Default: "split-char"

A class to apply to each split char component.

wordClass

Default: "split-word"

A class to apply to each split word component.

lineClass

Default: "split-line"

A class to apply to each split line component.

splitText is a tiny (+0.7kb) utility that makes it simple to create complex, beautiful split text animations with Motion.

Break down text into individual characters, words, and lines, to create staggered enter or scroll-driven text effects with just a few lines of code.

splitText is exclusive to Motion+ members. Motion+ is a one-time payment, lifetime membership that unlocks exclusive components, premium examples and access to a private Discord community.

Features

  • Animate anything: Split text into characters, words and lines to animate each independently.

  • Lightweight: Only adds 0.7kb to your project bundle.

  • Simple API: A clean API leaves your code maintainable.

  • Accessible: Correctly applies ARIA tags to leave your text readable for all users.

  • Flexible: Animate with Motion, CSS, or a library of your choice.

Install

First, add the Motion+ library to your project using your private token. You need to be a Motion+ member to generate a private token.

npm install https://api.motion.dev/registry\?package\=motion-plus\&version\=1.5.4\&token

Once installed, splitText can be imported via motion-plus:

import { splitText } from "motion-plus"

Usage

splitText accepts a CSS selector or an HTML Element. It replaces the element's text content with <span> tags that wrap individual characters, words, and (optionally) lines.

It returns an object containing chars, words, and lines as arrays of elements, so they can be animated right away with Motion's animate and stagger functions.

const { chars } = splitText("h1")

animate(
  chars,
  { opacity: [0, 1], y: [10, 0] },
  { duration: 1, delay: stagger(0.05) }
)

The returned arrays are regular elements so you're not limited to animating them with Motion. You could animate them with CSS, or another animation library of your choice. Or, you could attach gesture recognisers to each element individually, for instance with Motion's hover function.

const { words } = splitText("h1")

hover(words, (wordElement) => {
  // Hover logic
})

Techniques & troubleshooting

Enter animations

To perform enter animations, it might be necessary to set the container to visibility: hidden via CSS until we're ready to animate.

.container {
  visibility: hidden;
}
document.querySelector(".container").style.visibility = "visible"

const { words } = splitText(".container")
animate(words, { opacity: [0, 1] })

Otherwise we might see a flash of visible text until our JS has loaded.

Working with custom fonts

If you have custom fonts that download after splitText is executed, it can be that the text is split incorrectly because the dimensions of the text have changed.

To fix this, we can await the browser's document.fonts.ready promise:

document.fonts.ready.then(() => {
  const { words } = splitText(element)

  animate(
    words,
    { y: [-10, 10] },
    { delay: stagger(0.04) }
  )
})

Targeting with CSS

Each split component will receive split-char, split-word and split-line classes so you can select them with CSS. Each component additionally receives a data-index of its position within the overall character, word or line lists respectively.

.split-char[data-index=3] {
  color: red;
}

The provided classes are configurable with the charClass, wordClass and lineClass options.

splitText(element, { charClass: "my-char-class" })

splitText doesn't currently preserve existing tags within the text, so links and other styling spans will be removed.

It's possible to fix this by wrapping the text before/after the tag with its own span and splitting these individually:

<h2>
  <span class="before">Before</span>
  <a href="#">Link</a>
  <span class="after">After</span>
</h2>

<script>
  const chars = [
    ...splitText(".before").chars,
    ...splitText("a").chars,
    ...splitText(".after").chars,
  ]
</script>

SVG <text /> isn't working

<text /> elements are not supported.

text-align: justify is being lost

Splitting test in this way is incompatible with how browsers handle text-align: justify. You can implement something similar by adding styles for split-line:

.align-justify .split-line {
  display: flex;
  justify-content: space-between;
}

Options

splitBy

Default: " " (space)

The string to split the text by.

<p>My+custom+text</p>
splitText(paragraph, { splitBy: "+" })

Note: When splitting with a custom character, lines might start to wrap. Ensure the wrapper element is set to text-wrap: nowrap to keep text on a single line.

charClass

Default: "split-char"

A class to apply to each split char component.

wordClass

Default: "split-word"

A class to apply to each split word component.

lineClass

Default: "split-line"

A class to apply to each split line component.

splitText is a tiny (+0.7kb) utility that makes it simple to create complex, beautiful split text animations with Motion.

Break down text into individual characters, words, and lines, to create staggered enter or scroll-driven text effects with just a few lines of code.

splitText is exclusive to Motion+ members. Motion+ is a one-time payment, lifetime membership that unlocks exclusive components, premium examples and access to a private Discord community.

Features

  • Animate anything: Split text into characters, words and lines to animate each independently.

  • Lightweight: Only adds 0.7kb to your project bundle.

  • Simple API: A clean API leaves your code maintainable.

  • Accessible: Correctly applies ARIA tags to leave your text readable for all users.

  • Flexible: Animate with Motion, CSS, or a library of your choice.

Install

First, add the Motion+ library to your project using your private token. You need to be a Motion+ member to generate a private token.

npm install https://api.motion.dev/registry\?package\=motion-plus\&version\=1.5.4\&token

Once installed, splitText can be imported via motion-plus:

import { splitText } from "motion-plus"

Usage

splitText accepts a CSS selector or an HTML Element. It replaces the element's text content with <span> tags that wrap individual characters, words, and (optionally) lines.

It returns an object containing chars, words, and lines as arrays of elements, so they can be animated right away with Motion's animate and stagger functions.

const { chars } = splitText("h1")

animate(
  chars,
  { opacity: [0, 1], y: [10, 0] },
  { duration: 1, delay: stagger(0.05) }
)

The returned arrays are regular elements so you're not limited to animating them with Motion. You could animate them with CSS, or another animation library of your choice. Or, you could attach gesture recognisers to each element individually, for instance with Motion's hover function.

const { words } = splitText("h1")

hover(words, (wordElement) => {
  // Hover logic
})

Techniques & troubleshooting

Enter animations

To perform enter animations, it might be necessary to set the container to visibility: hidden via CSS until we're ready to animate.

.container {
  visibility: hidden;
}
document.querySelector(".container").style.visibility = "visible"

const { words } = splitText(".container")
animate(words, { opacity: [0, 1] })

Otherwise we might see a flash of visible text until our JS has loaded.

Working with custom fonts

If you have custom fonts that download after splitText is executed, it can be that the text is split incorrectly because the dimensions of the text have changed.

To fix this, we can await the browser's document.fonts.ready promise:

document.fonts.ready.then(() => {
  const { words } = splitText(element)

  animate(
    words,
    { y: [-10, 10] },
    { delay: stagger(0.04) }
  )
})

Targeting with CSS

Each split component will receive split-char, split-word and split-line classes so you can select them with CSS. Each component additionally receives a data-index of its position within the overall character, word or line lists respectively.

.split-char[data-index=3] {
  color: red;
}

The provided classes are configurable with the charClass, wordClass and lineClass options.

splitText(element, { charClass: "my-char-class" })

splitText doesn't currently preserve existing tags within the text, so links and other styling spans will be removed.

It's possible to fix this by wrapping the text before/after the tag with its own span and splitting these individually:

<h2>
  <span class="before">Before</span>
  <a href="#">Link</a>
  <span class="after">After</span>
</h2>

<script>
  const chars = [
    ...splitText(".before").chars,
    ...splitText("a").chars,
    ...splitText(".after").chars,
  ]
</script>

SVG <text /> isn't working

<text /> elements are not supported.

text-align: justify is being lost

Splitting test in this way is incompatible with how browsers handle text-align: justify. You can implement something similar by adding styles for split-line:

.align-justify .split-line {
  display: flex;
  justify-content: space-between;
}

Options

splitBy

Default: " " (space)

The string to split the text by.

<p>My+custom+text</p>
splitText(paragraph, { splitBy: "+" })

Note: When splitting with a custom character, lines might start to wrap. Ensure the wrapper element is set to text-wrap: nowrap to keep text on a single line.

charClass

Default: "split-char"

A class to apply to each split char component.

wordClass

Default: "split-word"

A class to apply to each split word component.

lineClass

Default: "split-line"

A class to apply to each split line component.

Related topics

Previous

mix

Next

spring

Motion+

Motion+

Motion+

Level up your animations with Motion+

Unlock the full vault of 290+ Motion examples, premium APIs, private Discord and GitHub, and powerful VS Code animation editing tools.

One-time payment, lifetime updates.

Motion is supported by the best in the industry.