Vertical Text Slider
Slides through an list of text vertically, pausing briefly on each item before transitioning to the next.
1. Copy the component file
Create a new file called vertical-text-slider.jsx in
your reusable components folder (for example
/src/components/) and paste the following code
into it.
vertical-text-slider.jsx
import { memo, useState, useEffect, useRef, useMemo } from "react";
import styles from "./vertical-text-slider.module.css";
const VerticalTextSlider = (props) => {
const {
texts,
direction = "up",
visibleDuration = 2000,
className,
style,
...restProps
} = props;
const transitionDurationMs = 250;
const [currentTextIndex, setCurrentTextIndex] = useState(0);
const wordNodeRef = useRef();
const wordDirectionClassName = useMemo(() => (
`direction-${direction === "down" ? "down" : "up"}`
), [direction]);
const totalAnimationDuration = useMemo(() => (
Math.max(transitionDurationMs * 4, visibleDuration)
), [transitionDurationMs, visibleDuration]);
useEffect(() => {
let animationOutTimeoutId = null, animationEndTimeoutId = null;
const animationInTimeoutId = setTimeout(() => {
wordNodeRef.current.classList.add(styles["pause"]);
animationOutTimeoutId = setTimeout(() => {
wordNodeRef.current.classList.remove(styles["pause"]);
wordNodeRef.current.style.animationName = styles[
`text-slide-${direction === "down" ? "up" : "down"}-keyframes`
];
animationEndTimeoutId = setTimeout(() => {
setCurrentTextIndex(
(currentTextIndex + 1) % texts.length
);
}, transitionDurationMs);
}, totalAnimationDuration - (transitionDurationMs * 2));
}, transitionDurationMs);
return () => {
clearTimeout(animationInTimeoutId);
clearTimeout(animationOutTimeoutId);
clearTimeout(animationEndTimeoutId);
};
}, [
texts.length,
currentTextIndex,
direction,
totalAnimationDuration,
]);
useEffect(() => {
setCurrentTextIndex(0);
}, [
texts,
visibleDuration,
direction
]);
return (
<span
{...restProps}
className={[
className,
styles["vertical-text-slider"]
].join(" ")}
style={{
...style,
"--sliding-animation-duration": `${transitionDurationMs}ms`
}}
>
<span
ref={wordNodeRef}
key={`word-${currentTextIndex}`}
className={[
styles["text"],
styles[wordDirectionClassName]
].join(" ")}
>
{texts[currentTextIndex]}
</span>
</span>
);
};
export default memo(
VerticalTextSlider,
(prevProps, nextProps) => {
const { texts: prevTexts, ...restPrevProps } = prevProps;
const { texts: nextTexts, ...restNextProps } = nextProps;
const prevKeys = Object.keys(restPrevProps);
const nextKeys = Object.keys(restNextProps);
const areRestEqual = (
prevKeys.length === nextKeys.length &&
prevKeys.every(prop => (
prevProps[prop] === nextProps[prop]
))
);
if(
Array.isArray(prevTexts) &&
Array.isArray(nextTexts)
) {
return (
areRestEqual &&
prevTexts.every((text, index) => (
text === nextTexts[index]
))
);
}
return areRestEqual;
},
); 2. Copy the CSS module file
In the same folder, create a file called vertical-text-slider.module.css and paste the following CSS.
vertical-text-slider.module.css
.vertical-text-slider {
--sliding-animation-duration: 250ms;
> .text {
display: inline-block;
word-break: keep-all;
animation-duration: var(--sliding-animation-duration);
animation-timing-function: ease-in-out;
animation-fill-mode: forwards;
&.direction-down {
opacity: 0;
transform: translateY(-50%);
animation-name: text-slide-down-keyframes;
}
&.direction-up {
opacity: 0;
transform: translateY(50%);
animation-name: text-slide-up-keyframes;
animation-direction: reverse;
}
&.pause {
opacity: 1 !important;
transform: translateY(0%) !important;
animation: unset;
}
}
}
@keyframes text-slide-up-keyframes {
0% {
opacity: 1;
transform: translateY(0%);
}
100% {
opacity: 0;
transform: translateY(50%);
}
}
@keyframes text-slide-down-keyframes {
0% {
opacity: 0;
transform: translateY(-50%);
}
100% {
opacity: 1;
transform: translateY(0%);
}
} 3. Use the component
Now you can import and use the component anywhere in your project.
vertical-text-slider-preview.jsx
import VerticalTextSlider from "@/components/text-effects/vertical-text-slider/vertical-text-slider";
const VerticalTextSliderPreview = () => {
return (
<h2>
<VerticalTextSlider
texts={[
"Build faster",
"Ship smarter",
"Scale confidently",
"Delight users"
]}
/>
</h2>
);
};
export default VerticalTextSliderPreview; Down Direction
vertical-text-slider
import VerticalTextSlider from "@/components/text-effects/vertical-text-slider/vertical-text-slider";
const VerticalTextSliderDownDirectionPreview = () => {
return (
<h2>
<VerticalTextSlider
texts={[
"Build faster",
"Ship smarter",
"Scale confidently",
"Delight users"
]}
direction="down"
/>
</h2>
);
};
export default VerticalTextSliderDownDirectionPreview; Custom Visible Duration
vertical-text-slider
import VerticalTextSlider from "@/components/text-effects/vertical-text-slider/vertical-text-slider";
const VerticalTextSliderVisibleDurationPreview = () => {
return (
<h2>
<VerticalTextSlider
texts={[
"Build faster",
"Ship smarter",
"Scale confidently",
"Delight users"
]}
visibleDuration={5000}
/>
</h2>
);
};
export default VerticalTextSliderVisibleDurationPreview; Props
Configure the component with the following props:
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| texts | string[] | Yes | — | Array of text strings to display in the vertical slider. |
| direction | "up" | "down" | No | "up" | Slide direction. "up" slides text upward, "down" slides text downward. |
| visibleDuration | number | No | 2000 | Time (in milliseconds) each text remains fully visible before sliding out. Minimum: 1000ms. |
| className | string | No | — | Optional class name applied to the root container. |
| style | React.CSSProperties | No | — | Inline styles applied to the root container. |