Getting Started
Accordion
Barricade Tape
Buttons
Browser Window
Contact Section
File Stack
Glass Grid
NewGooey Words
Glowing Dots Background
Image Pile
Jelly Loader
Mask Cursor Effect
NewMagnet Tabs
Masonry Grid
Pixelated Carousel
NewPixelated Text
NewPrismatic Haze Background
Projects Section
Proximity Background
Proximity Lift Grid
Sentence Flip
NewSkeumorphic Music Card
Spider Loader
NewSpotlight Grid
Texts
Trading Card
Wavy Background
NewSentence Flip
A dynamic, animated text component that creates engaging sentence transitions with word-by-word flipping animations. Built with Framer Motion, this React component cycles through multiple sentences, highlighting specific words with custom styling and smooth blur transitions. Perfect for hero sections, landing pages, and interactive content displays where you want to showcase different messaging variations with elegant motion effects.
Preview
Install dependencies
npm i framer-motion
Component
Create a file sentence-flip.tsx in your components folder and paste this code
'use client';
import { cn } from '@/lib/utils';
import { AnimatePresence, motion } from 'framer-motion';
import { Raleway } from 'next/font/google';
import React, { useEffect, useRef, useState } from 'react';
const raleway = Raleway({
subsets: ['latin'],
weight: ['400', '500', '600', '700', '800', '900']
});
const WordFlipper = ({
words,
wordIndex
}: {
words: { word: string; isHighlighted: boolean }[];
wordIndex: number;
}) => {
const wordRef = useRef<HTMLDivElement>(null);
const [wordHeight, setWordHeight] = useState(0);
const [currentIndex, setCurrentIndex] = useState(0);
useEffect(() => {
if (!wordRef.current) return;
setWordHeight(wordRef.current.clientHeight);
window.addEventListener('resize', () => {
if (!wordRef.current) return;
setWordHeight(wordRef.current.clientHeight);
});
return () => {
window.removeEventListener('resize', () => {
if (!wordRef.current) return;
setWordHeight(wordRef.current.clientHeight);
});
};
}, [wordRef]);
useEffect(() => {
const interval = setInterval(() => {
setCurrentIndex((prev) => (prev + 1) % words.length);
}, 1500);
return () => clearInterval(interval);
}, [words]);
return (
<motion.div layout="position" className="text-3xl md:text-4xl lg:text-5xl relative">
<p ref={wordRef} className="text-transparent opacity-0 select-none absolute">
sample
</p>
<div
style={{
height: wordHeight
}}
className="overflow-hidden"
>
<AnimatePresence mode="popLayout">
{words.map((word, index) => {
if (index === currentIndex) {
return (
<motion.p
key={'word' + index}
initial={{ opacity: 0, filter: 'blur(10px)', y: wordHeight / 2 }}
animate={{ opacity: 1, filter: 'blur(0px)', y: 0 }}
exit={{ opacity: 0, filter: 'blur(10px)', y: -wordHeight / 2 }}
transition={{
duration: 0.1,
ease: 'easeInOut',
delay: wordIndex * 0.1
}}
className={cn(
'py-0.5',
word.isHighlighted
? `${raleway.className} font-semibold text-blue-500`
: `${raleway.className} font-light`
)}
>
{word.word}
</motion.p>
);
} else return null;
})}
</AnimatePresence>
</div>
</motion.div>
);
};
const SentenceFlip = ({
sentences
}: {
sentences: { sentence: string; highlight: number[] }[];
}) => {
// contains the words length of the sentence that is longest
const [words, setWords] = useState(0);
useEffect(() => {
const longestSentence = sentences.reduce((longest, { sentence }) => {
return sentence.length > longest.length ? sentence : longest;
}, '');
setWords(longestSentence.split(' ').length);
}, [sentences]);
return (
<div className="w-full flex flex-col justify-center">
<div className="max-w-3xl place-self-center w-full">
<div className="flex flex-wrap gap-x-2 justify-start">
{Array.from({ length: words }).map((_, index) => {
const wordsToFlip = sentences.map((sentence) => {
const splits = sentence.sentence.split(' ');
const isHighlighted = sentence.highlight.includes(index);
if (splits.length > index) {
return { word: splits[index], isHighlighted };
}
return { word: '', isHighlighted: false };
});
return (
<React.Fragment key={'sentence' + index}>
<WordFlipper words={wordsToFlip} wordIndex={index} />
{(index + 1) % 4 === 0 && <div className="w-full" />}
</React.Fragment>
);
})}
</div>
</div>
</div>
);
};
export default SentenceFlip;
Usage
<SentenceFlip
sentences={[
{ sentence: 'The home for your AI assistants', highlight: [1, 4, 5] },
{ sentence: 'Build personal AI assistants your way', highlight: [1, 2, 3] },
{ sentence: 'Build smarter assistants, your unique way', highlight: [1, 2] },
{ sentence: 'Create custom AI with custom prompts', highlight: [2, 4, 5] },
{ sentence: 'Break free from Generic AI', highlight: [3, 4] }
]}
/>