Reveal
Scroll-triggered fade-and-slide, plus a Stagger for groups.
$
pnpm dlx shadcn@latest add https://lodeui.com/r/reveal.jsonScroll-triggered entrances
1Sign up
2Create a workspace
3Invite your team
4Ship
components/examples/reveal-demo.tsx
"use client";
import { Reveal, Stagger } from "@/components/ui/reveal";
export default function RevealDemo() {
return (
<div className="w-full max-w-md space-y-4">
<Reveal><h3 className="text-xl font-semibold">Scroll-triggered entrances</h3></Reveal>
<Stagger className="space-y-2">
{["Sign up", "Create a workspace", "Invite your team", "Ship"].map((s, i) => (
<div key={s} className="flex items-center gap-3 rounded-lg border border-border bg-card p-3 text-sm"><span className="grid size-6 place-items-center rounded-full bg-muted font-mono text-xs">{i + 1}</span>{s}</div>
))}
</Stagger>
</div>
);
}When to use
- Sections that fade in as you scroll a landing page.
When not to use
- App UI people use every day.
Installation
$
pnpm dlx shadcn@latest add https://lodeui.com/r/reveal.json1Install the dependencies
npm install motion2Copy the source into your project
components/ui/reveal.tsx"use client"; import * as React from "react"; import { motion, useReducedMotion } from "motion/react"; export interface RevealProps { children: React.ReactNode; /** Direction it comes from. */ from?: "bottom" | "left" | "right" | "none"; delay?: number; className?: string; } /** Fades and slides children in when they scroll into view, once. */ export function Reveal({ children, from = "bottom", delay = 0, className }: RevealProps) { const reduce = useReducedMotion(); const offset = { bottom: { y: 16 }, left: { x: -16 }, right: { x: 16 }, none: {} }[from]; return ( <motion.div className={className} initial={reduce ? false : { opacity: 0, ...offset }} whileInView={{ opacity: 1, x: 0, y: 0 }} viewport={{ once: true, margin: "-8% 0px" }} transition={{ delay, duration: 0.5, ease: [0.2, 0.8, 0.2, 1] }} > {children} </motion.div> ); } /** Staggers its direct children in as a group. */ export function Stagger({ children, gap = 0.06, className }: { children: React.ReactNode; gap?: number; className?: string }) { const reduce = useReducedMotion(); return ( <motion.div className={className} initial={reduce ? false : "hidden"} whileInView="show" viewport={{ once: true, margin: "-8% 0px" }} variants={{ hidden: {}, show: { transition: { staggerChildren: gap } } }} > {React.Children.map(children, (child) => ( <motion.div variants={{ hidden: { opacity: 0, y: 12 }, show: { opacity: 1, y: 0, transition: { duration: 0.4, ease: [0.2, 0.8, 0.2, 1] } } }}>{child}</motion.div> ))} </motion.div> ); }
Usage
Import it from @/components/ui/reveal after installing.
example.tsx
import { Reveal, Stagger } from "@/components/ui/reveal";
export function Features() {
return (
<Reveal>
<Stagger className="grid gap-4 sm:grid-cols-3">
<div>One</div>
<div>Two</div>
<div>Three</div>
</Stagger>
</Reveal>
);
}API reference
Reveal
Fades its children in when they scroll into view.
| Prop | Type | Default | Description |
|---|---|---|---|
| from | "bottom" | "left" | "right" | "none" | "bottom" | Direction. |
| delay | number | 0 | Seconds. |
Stagger
Reveals direct children one after another.
| Prop | Type | Default | Description |
|---|---|---|---|
| gap | number | 0.06 | Seconds between children. |
Accessibility
- Content is shown at once under reduced motion.
Motion
- Fades and slides 16px once per page view.
Responsive behavior
- Works in any layout.
Performance
- IntersectionObserver; animates once.
Notes for AI
- Don't wrap above-the-fold content; it delays first paint.
This page as Markdown, for assistants and coding agents:
/components/reveal/markdownThe full library index for assistants is at /llms.txt.
Lode222 doc pagesllms.txt