Slide In Text
Animates text sliding in from the left with a fade when it enters the viewport.
Component
↓ scroll
Los Flamencos National Reserve
is a nature reserve located
in the commune of San Pedro de Atacama.
The reserve covers a total area
of 740 square kilometres.
"use client";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { useLayoutEffect, useRef } from "react";
import { cn } from "@/lib/utils";
interface SlideInTextProps {
children: React.ReactNode;
className?: string;
left?: string;
y?: string;
opacity?: number;
ease?: string;
scrub?: boolean | number;
start?: string;
end?: string;
}
export function SlideInText({
children,
className,
left = "-200px",
y,
opacity = 0,
ease = "power3.out",
scrub = true,
start = "0px bottom",
end = "bottom+=400px bottom",
}: SlideInTextProps) {
const ref = useRef<HTMLParagraphElement>(null);
useLayoutEffect(() => {
gsap.registerPlugin(ScrollTrigger);
const ctx = gsap.context(() => {
gsap.from(ref.current, {
ease,
left,
...(y !== undefined && { y }),
opacity,
scrollTrigger: {
end,
scrub,
start,
trigger: ref.current,
},
});
});
return () => ctx.revert();
}, [left, y, opacity, ease, scrub, start, end]);
return (
<p ref={ref} className={cn("relative", className)}>
{children}
</p>
);
}Installation
pnpm dlx shadcn@latest add "https://pulkitxm.com/components/slide-in-text.json"1. Install dependencies
pnpm add gsap2. Copy the component file
"use client";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { useLayoutEffect, useRef } from "react";
import { cn } from "@/lib/utils";
interface SlideInTextProps {
children: React.ReactNode;
className?: string;
left?: string;
y?: string;
opacity?: number;
ease?: string;
scrub?: boolean | number;
start?: string;
end?: string;
}
export function SlideInText({
children,
className,
left = "-200px",
y,
opacity = 0,
ease = "power3.out",
scrub = true,
start = "0px bottom",
end = "bottom+=400px bottom",
}: SlideInTextProps) {
const ref = useRef<HTMLParagraphElement>(null);
useLayoutEffect(() => {
gsap.registerPlugin(ScrollTrigger);
const ctx = gsap.context(() => {
gsap.from(ref.current, {
ease,
left,
...(y !== undefined && { y }),
opacity,
scrollTrigger: {
end,
scrub,
start,
trigger: ref.current,
},
});
});
return () => ctx.revert();
}, [left, y, opacity, ease, scrub, start, end]);
return (
<p ref={ref} className={cn("relative", className)}>
{children}
</p>
);
}3. Import and use
import { SlideInText } from "@/components/slide-in-text";
<SlideInText>Your text here</SlideInText>;Usage
Import the component
Add the SlideInText import to your file.
import { SlideInText } from "@/components/slide-in-text";Use with default props
Wrap your text in SlideInText for the default slide-in animation.
<SlideInText>Your text here</SlideInText>;Customize with props
Adjust left, scrub, start, and end to fine-tune the animation.
<SlideInText
left="-400px"
scrub={0.5}
start="top 80%"
end="bottom+=200px bottom"
>
Custom animated text
</SlideInText>;Guidelines
- Place SlideInText inside a scrollable container (e.g. your main content area or a div with overflow-y-auto).
- Use scrub: true for smooth scroll-linked animation, or a number (e.g. 0.5) for a slight delay.
- Adjust left to control how far the text slides in from (e.g. -200px, -400px).
- Customize start and end to change when the animation triggers relative to the viewport.
Props
All props are optional unless marked required. Use these to customize every aspect of the component.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | React.ReactNode | — | Content to render inside the paragraph. |
| className | string | — | Additional CSS classes applied to the element. |
| left | string | "-200px" | CSS left offset to animate from. Passed directly to GSAP. |
| y | string | — | CSS y offset to animate from (e.g. '20px'). Omit for no vertical animation. |
| opacity | number | 0 | Initial opacity before animation (0–1). |
| ease | string | "power3.out" | GSAP ease applied to the scrub. |
| scrub | boolean | number | true | ScrollTrigger scrub value. true = smooth, number = seconds to catch up. |
| start | string | "0px bottom" | ScrollTrigger start position. |
| end | string | "bottom+=400px bottom" | ScrollTrigger end position. |
Examples
Basic
Default usage with standard scroll range and ease.
↓ scroll
Los Flamencos National Reserve
is a nature reserve located
in the commune of San Pedro de Atacama.
The reserve covers a total area
of 740 square kilometres.
import { SlideInText } from "@/components/slide-in-text";
export function SlideInTextBasic() {
return (
<div className="space-y-8">
<SlideInText>First line of text</SlideInText>
</div>
);
}Custom offset
Slide further with a faster scrub for snappier animation.
↓ scroll
Los Flamencos National Reserve
is a nature reserve located
in the commune of San Pedro de Atacama.
The reserve covers a total area
of 740 square kilometres.
import { SlideInText } from "@/components/slide-in-text";
export function SlideInTextCustomOffset() {
return (
<SlideInText left="-400px" scrub={0.5}>
Second line
</SlideInText>
);
}Custom scroll range
Control when the animation starts and ends relative to viewport.
↓ scroll
Los Flamencos National Reserve
is a nature reserve located
in the commune of San Pedro de Atacama.
The reserve covers a total area
of 740 square kilometres.
import { SlideInText } from "@/components/slide-in-text";
export function SlideInTextCustomRange() {
return (
<SlideInText start="top 80%" end="bottom+=200px bottom">
Third line
</SlideInText>
);
}