Skip to content

Reveal

Animate content in as it loads or scrolls into view, and out as it leaves, with fades, slides, blur and more.

Use it for content that should arrive rather than appear: a hero's headline, a section as it scrolls in, a panel that opens. One Reveal moves one element. For a group, use Stagger, and for a headline that assembles word by word, TextSplit. Don't reveal what people came to read or act on, like form fields, table rows or navigation. It should be there when they look.

Installation

npm i @youj/motion

import { Reveal, RevealMotionOptions } from '@youj/motion'

For an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.

Usage

Wrap anything. By default it rises into place the first time 30% of it is on screen.

import { Reveal } from '@youj/motion'

export function Feature() {
  return (
    <Reveal>
      <FeatureCard />
    </Reveal>
  )
}

Use inView={false} for content that should arrive as soon as it renders, and as to reveal a heading or list item without an extra wrapper.

<Reveal as="h2" inView={false} className="text-4xl font-semibold">
  Motion that lands where you meant it.
</Reveal>

Examples

Variants

Eight arrivals share one timing model. rise, fade and scale take the slow duration. The four wipe-* variants and blur-in travel further, so they take deliberate. Everything that travels decelerates hard into place on the enter curve. fade doesn't travel, so it uses standard.

Reference

Propsas, variant, inView… (12)

Props

Reveal props
PropType
asRevealTag
'div''span''section''article''header''footer''li''p''h1''h2''h3''figure'

default 'div'

'div'
variantRevealVariant
'fade''rise''blur-in''scale''wipe-up''wipe-down''wipe-left''wipe-right'

default 'rise'

'rise'
inViewInView

When it plays: false on mount; true (the default) when scrolled into view, once, at 30% visible; or { once, amount, margin }.

–
delaynumber

Delay as a multiple of the delayStep stagger token. delay={2} = two steps.

default 0

0
delayStepStaggerToken
'tight''base''loose'

default 'base'

'base'
durationDurationToken
'instant''fast''base''slow''deliberate'
–
easeEasingToken
'standard''enter''exit''emphasized''linear'
–
distancenumber | string

Travel for rise (px or any CSS length, e.g. '110%' for masked lines).

default 12

12
childrenReactNode–
Other props pass through: extends HTMLMotionProps<'div'>.

distance, how far rise travels, defaults to 12 (px).

MotionEnter, enter, long travel, fade… · reduced motion

Motion

Motion tokens
MomentTokens
Enterrise, scale
duration.slowease.enter

340ms · cubic-bezier(0.16, 1, 0.3, 1)

340mscubic-bezier(0.16, 1, 0.3, 1)
Enter, long travelblur-in, wipe-*
duration.deliberateease.enter

560ms · cubic-bezier(0.16, 1, 0.3, 1)

560mscubic-bezier(0.16, 1, 0.3, 1)
Fadeopacity only
duration.slowease.standard

340ms · cubic-bezier(0.2, 0, 0, 1)

340mscubic-bezier(0.2, 0, 0, 1)
Exit
duration.fastease.exit

140ms · cubic-bezier(0.4, 0, 1, 1)

140mscubic-bezier(0.4, 0, 1, 1)
Delay stepdefault delayStep
stagger.base

40ms step

40ms step

Reduced motion

Renders in its final state: no fade, no travel. Presence exits remove the element immediately.

It animates only opacity, transform, filter and clip-path, so a reveal never triggers layout.

Reduced motion

A Reveal renders in its final state from the first frame: no fade, no travel and no wait. Inside AnimatePresence, it's removed at once. Nothing is hidden behind a scroll position, so the page reads the same either way.

AccessibilityARIA

Accessibility

  • The content is in the document from the first render, so assistive technology reads it whether or not it has animated in.
  • Reveal adds no roles. Put semantics on the element itself, with as.
  • Scroll reveals are one-shot by default (inView={{ once: true }}). Content that disappears as it scrolls away makes a page feel unstable, so opt out only with a reason.