Guides
Animations
trink-ui includes a set of animation wrappers that add smooth entrance effects to your sections. Learn how to use FadeIn, SlideUp, StaggerChildren, ScaleIn, and BlurIn effectively.
Available animation wrappers
Each wrapper is a React component that animates its children when they enter the viewport:
FadeInFades content from transparent to opaque
SlideUpSlides content upward while fading in
ScaleInScales content from slightly smaller to full size
BlurInTransitions from blurred to sharp while fading in
StaggerChildrenAnimates a list of children with sequential delay
Basic usage
Wrap any content with an animation component. By default, animations trigger when the element scrolls into view:
import { FadeIn, SlideUp, ScaleIn, BlurIn } from "@trinkui/react";
// Simple fade in on scroll
<FadeIn>
<h2>This heading fades in</h2>
</FadeIn>
// Slide up with fade
<SlideUp>
<p>This paragraph slides up into view</p>
</SlideUp>
// Scale from small to full size
<ScaleIn>
<img src="/hero.png" alt="Hero image" />
</ScaleIn>
// Blur to sharp transition
<BlurIn>
<div className="card">Content appears from blur</div>
</BlurIn>Scroll trigger behavior
By default, animations use scrollTrigger={true} to animate when the element enters the viewport, and once={true} so the animation only plays once. You can change this behavior:
// Animate immediately (no scroll trigger)
<FadeIn scrollTrigger={false}>
<h1>Above-the-fold content</h1>
</FadeIn>
// Re-animate every time the element enters the viewport
<SlideUp once={false}>
<div>Animates every scroll pass</div>
</SlideUp>Controlling delay and duration
Fine-tune timing with the delay and duration props (in seconds):
// Fast animation with no delay
<FadeIn duration={0.3} delay={0}>
<p>Quick fade</p>
</FadeIn>
// Slow, dramatic entrance
<SlideUp duration={1.2} delay={0.5}>
<h2>Dramatic headline</h2>
</SlideUp>
// Sequenced elements with manual delays
<FadeIn delay={0}>
<h2>Title appears first</h2>
</FadeIn>
<FadeIn delay={0.2}>
<p>Subtitle appears second</p>
</FadeIn>
<FadeIn delay={0.4}>
<button>Button appears third</button>
</FadeIn>Stagger pattern for lists and grids
Use StaggerChildren to animate a list of items with sequential delay. Each direct child is animated one after another:
import { StaggerChildren } from "@trinkui/react";
<StaggerChildren staggerDelay={0.1}>
{features.map((feature) => (
<div key={feature.title} className="rounded-lg border p-6">
<h3>{feature.title}</h3>
<p>{feature.description}</p>
</div>
))}
</StaggerChildren>The staggerDelay prop controls the time between each child's animation start. The default is 0.1 seconds.
Disabling animations
There are three ways to disable animations:
1. Per-section with the animated prop
Every section component accepts animated={false} to render without any animation wrappers.
2. Automatic reduced motion detection
All animation wrappers call useReducedMotion() internally. If the user has enabled "Reduce motion" in their OS settings, animations are automatically replaced with a plain <div>.
3. CSS media query fallback
As an additional safety net, you can add a CSS rule to instantly show all animated elements when reduced motion is preferred.
// Section with no animations
<HeroCentered animated={false} title="Instant render" ... />
// Animation wrapper that auto-detects reduced motion
<FadeIn>
{/* Renders as plain <div> when user prefers reduced motion */}
<p>Content here</p>
</FadeIn>Performance considerations
trink-ui animations are designed for performance:
- Only opacity and transform are animated — these are GPU-composited properties that do not trigger layout recalculation
- Intersection Observer is used for scroll triggers instead of scroll event listeners
- Animations run once by default, so no ongoing computation after the initial render
- The useReducedMotion hook prevents unnecessary animation setup for users who prefer reduced motion
Combining multiple animation types
Use different animation types for different elements in the same section to create visual hierarchy:
import { FadeIn, SlideUp, ScaleIn, StaggerChildren } from "@trinkui/react";
function CustomSection() {
return (
<section className="py-20">
<div className="mx-auto max-w-6xl px-4">
{/* Headline slides up first */}
<SlideUp delay={0}>
<h2 className="text-4xl font-bold text-center">Our Features</h2>
</SlideUp>
{/* Subtitle fades in after */}
<FadeIn delay={0.2}>
<p className="mt-4 text-center text-lg text-gray-600">
Everything you need to succeed.
</p>
</FadeIn>
{/* Feature cards stagger in */}
<StaggerChildren staggerDelay={0.15} className="mt-12 grid gap-6 md:grid-cols-3">
<div className="rounded-xl border p-6">
<ScaleIn>
<div className="text-4xl">⚡</div>
</ScaleIn>
<h3 className="mt-4 font-semibold">Fast</h3>
<p className="mt-2 text-sm text-gray-500">Lightning quick performance.</p>
</div>
<div className="rounded-xl border p-6">
<ScaleIn>
<div className="text-4xl">🎨</div>
</ScaleIn>
<h3 className="mt-4 font-semibold">Beautiful</h3>
<p className="mt-2 text-sm text-gray-500">Polished design system.</p>
</div>
<div className="rounded-xl border p-6">
<ScaleIn>
<div className="text-4xl">🔒</div>
</ScaleIn>
<h3 className="mt-4 font-semibold">Secure</h3>
<p className="mt-2 text-sm text-gray-500">Enterprise-grade security.</p>
</div>
</StaggerChildren>
</div>
</section>
);
}Next step
Learn how trink-ui handles responsive design across all screen sizes.
Responsive Design Guide