Text Rotate
A text component that switches the rendered text from a list.
Make it work!
Installation
npx shadcn@latest add "https://fancycomponents.dev/r/text-rotate.json"
Understanding the component
-
For the animation, we switch the actual rendered text from the
texts
array. Either automatically, if theauto
prop is set totrue
, or we can do it manually, by calling thenext()
orprevious()
methods exposed via a ref. -
For animating out the previous text, and animating in the next, we use the
AnimatePresence
component frommotion/react
. Theinitial
,animate
andexit
props can be used to define the three states of the text. Refer to the motion documentation for more details. -
The current text is split into smaller pieces based on the
splitBy
prop, which will determine how the text will be animated:words
: Splits into individual words (e.g., "Hello world" → ["Hello", "world"])characters
: Splits into individual characters (e.g., "Hi" → ["H", "i"])lines
: Splits by newline characters (\n
)string
: Splits by any custom string delimiter
-
Each piece of text is wrapped in two
<span>
elements: An outer<span>
that acts as a container for a word or line of text and an inner<span>
that holds the actual text. There are two reasons for this:- When dealing with multi-line text, each line maintains its own reveal animation starting point. This means if you have text that spans multiple lines, each line will animate independently from its own baseline, rather than all elements animating from a single point (like the bottom of the entire paragraph).
- When using
characters
mode, characters from the same word stay together in a word container. This prevents unwanted line breaks in the middle of words - if a word needs to wrap to the next line, it will wrap as a complete unit rather than having some characters on one line and others on the next line. This maintains proper text flow and readability while still allowing character-by-character animation within each word.
Examples
SplitBy variations
With the splitBy
prop, you can control how the text is split into smaller pieces. It can be either words
, characters
, lines
, or a custom string
delimiter. In case of lines
, you are responsible for adding the \n
delimiter yourself.
The following example demonstrates the words
(the quote) and characters
(the author) mode. It should respect multiline texts.
Stagger
With the staggerFrom
prop, you can control the index of the letter/word/line where the stagger animation starts. Possible values are "first"
, "center"
, "last"
, "random"
, or a number.
Manual control
If the auto
prop is set to false
, you can manually control the animation by calling the next()
or previous()
methods exposed via a ref.
this is the first text
This can be handy for a lot of use cases, eg. a scroll-triggered animation.
Notes
If you're using auto
mode, make sure that the rotationInterval
prop is set to a value that's greater than the duration of initial/exit animations, otherwise we will switch to a new text before the animation is complete.
Props
TextRotateProps
Prop | Type | Default | Description |
---|---|---|---|
texts* | string[] | - | The text to be displayed and animated |
initial | MotionProps["initial"] | { y: "100%", opacity: 0 } | Initial styles for the text |
animate | MotionProps["animate"] | { y: 0, opacity: 1 } | Target styles for the text |
exit | MotionProps["exit"] | { y: "-120%", opacity: 0 } | Styles for the text for animating out |
animatePresenceMode | AnimatePresenceProps["mode"] | "wait" | The mode for the AnimatePresence component. Refer to motion docs for more details |
animatePresenceInitial | boolean | false | Whether to animate in the initial state for AnimatePresence. Refer to motion docs for more details |
rotationInterval | number | 2000 | The interval in milliseconds between each rotation |
transition | ValueAnimationTransition | { type: "spring", damping: 25, stiffness: 300 } | Animation configuration for each letter. Refer to motion docs for more details |
staggerDuration | number | 0 | Delay between each letter's animation start |
staggerFrom | "first" | "last" | "center" | "random" | number | "first" | Starting index of the stagger effect |
loop | boolean | true | Whether to loop through the texts |
auto | boolean | true | Whether to start the animation automatically |
splitBy | "words" | "characters" | "lines" | string | "words" | The split method for the text |
onNext | (index: number) => void | - | Callback function for when the next text is rendered |
mainClassName | string | - | Additional CSS classes for styling the container |
splitLevelClassName | string | - | Additional CSS classes for styling the individual words or lines |
elementLevelClassName | string | - | Additional CSS classes for styling the individual characters/words/lines |
TextRotateRef
Method | Description |
---|---|
next() | Goes to the next text |
previous() | Goes back to the previous text |
jumpTo(index: number) | Jumps to a specific text index |
reset() | Resets the animation to the initial state |