Content animating in as it enters the viewport.
Reveals from up as each card enters the viewport · 600ms
<div class="mot-rev-stage" data-direction="up">
<div class="mot-rev-item mot-rev-item--s1" style="border-color:#A8E6C1;">Card one</div>
<div class="mot-rev-item mot-rev-item--s2" style="border-color:#A8E6C1;">Card two</div>
<div class="mot-rev-item mot-rev-item--s3" style="border-color:#A8E6C1;">Card three</div>
<p class="mot-rev-caption">Reveals from up as each card enters the viewport · 600ms</p>
</div>
<style>
.mot-rev-stage { width: 100%; max-width: 320px; padding: 16px; background: #FAF7F2; border: 1px solid #24143022; border-radius: 12px; font: 12px system-ui, sans-serif; color: #241430aa; }
.mot-rev-item { background: #fff; border: 1.5px solid; border-radius: 8px; padding: 10px 12px; margin-bottom: 8px; font-size: 13px; color: #241430; }
.mot-rev-caption { margin: 10px 0 0; }
@media (prefers-reduced-motion: no-preference) {
[data-direction="up"] .mot-rev-item { animation: mot-rev-up 600ms ease-out both; }
[data-direction="left"] .mot-rev-item { animation: mot-rev-left 600ms ease-out both; }
[data-direction="scale"] .mot-rev-item { animation: mot-rev-scale 600ms ease-out both; }
.mot-rev-item--s1 { animation-delay: 0ms; }
.mot-rev-item--s2 { animation-delay: 150ms; }
.mot-rev-item--s3 { animation-delay: 300ms; }
@keyframes mot-rev-up { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: translateY(0); } }
@keyframes mot-rev-left { from { opacity: 0; transform: translateX(-24px); } to { opacity: 1; transform: translateX(0); } }
@keyframes mot-rev-scale { from { opacity: 0; transform: scale(.85); } to { opacity: 1; transform: scale(1); } }
}
</style><div class="w-full max-w-[320px] p-4 bg-[#FAF7F2] border border-[#24143022] rounded-xl font-sans text-xs text-[#241430]/70" data-direction="up">
<div class="tw-rev-item tw-rev-s1 bg-white border-[1.5px] rounded-lg px-3 py-2.5 mb-2 text-sm text-[#241430]" style="border-color:#A8E6C1;">Card one</div>
<div class="tw-rev-item tw-rev-s2 bg-white border-[1.5px] rounded-lg px-3 py-2.5 mb-2 text-sm text-[#241430]" style="border-color:#A8E6C1;">Card two</div>
<div class="tw-rev-item tw-rev-s3 bg-white border-[1.5px] rounded-lg px-3 py-2.5 mb-2 text-sm text-[#241430]" style="border-color:#A8E6C1;">Card three</div>
<p class="mt-2.5">Reveals from up as each card enters the viewport · 600ms</p>
</div>
<style>
@media (prefers-reduced-motion: no-preference) {
[data-direction="up"] .tw-rev-item { animation: mot-rev-tw-up 600ms ease-out both; }
[data-direction="left"] .tw-rev-item { animation: mot-rev-tw-left 600ms ease-out both; }
[data-direction="scale"] .tw-rev-item { animation: mot-rev-tw-scale 600ms ease-out both; }
.tw-rev-s1 { animation-delay: 0ms; }
.tw-rev-s2 { animation-delay: 150ms; }
.tw-rev-s3 { animation-delay: 300ms; }
@keyframes mot-rev-tw-up { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: translateY(0); } }
@keyframes mot-rev-tw-left { from { opacity: 0; transform: translateX(-24px); } to { opacity: 1; transform: translateX(0); } }
@keyframes mot-rev-tw-scale { from { opacity: 0; transform: scale(.85); } to { opacity: 1; transform: scale(1); } }
}
</style>export function ScrollReveal({
direction = "up",
duration = 600,
stagger = true,
accent = "#A8E6C1",
}) {
const anim = { up: "mot-rev-up", left: "mot-rev-left", scale: "mot-rev-scale" }[direction];
const items = ["Card one", "Card two", "Card three"];
return (
<div style={{ width: "100%", maxWidth: 320, padding: 16, background: "#FAF7F2", border: "1px solid #24143022", borderRadius: 12, fontFamily: "system-ui, sans-serif", fontSize: 12, color: "#241430aa" }}>
{items.map((label, i) => (
<div key={label} className={`item s${i + 1}`} style={{ background: "#fff", border: `1.5px solid ${accent}`, borderRadius: 8, padding: "10px 12px", marginBottom: 8, fontSize: 13, color: "#241430" }}>
{label}
</div>
))}
<p style={{ margin: "10px 0 0" }}>Reveals from {direction} as each card enters the viewport · {duration}ms</p>
<style>{`
@media (prefers-reduced-motion: no-preference) {
.item { animation: ${anim} ${duration}ms ease-out both; }
.s1 { animation-delay: ${stagger ? 0 : 0}ms; }
.s2 { animation-delay: ${stagger ? 150 : 0}ms; }
.s3 { animation-delay: ${stagger ? 300 : 0}ms; }
@keyframes mot-rev-up { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: translateY(0); } }
@keyframes mot-rev-left { from { opacity: 0; transform: translateX(-24px); } to { opacity: 1; transform: translateX(0); } }
@keyframes mot-rev-scale { from { opacity: 0; transform: scale(.85); } to { opacity: 1; transform: scale(1); } }
}
`}</style>
</div>
);
}