AnimateAppear
A list of things settling into place one after another. Each child gets the same short fade and drift, held back by its position, so the effect belongs to the set rather than to any one item.
import { AnimateAppear } from 'neba';
<AnimateAppear className="flex flex-col gap-2">
<Card title="Design review">Thursday, 14:00</Card>
<Card title="Sprint planning">Friday, 10:00</Card>
</AnimateAppear>;Props
| Prop | Type | Default | Description |
|---|---|---|---|
| fromshared | 'top' | 'right' | 'bottom' | 'left' | 'bottom' | Which edge each child drifts in from |
| distance | number | string | '0.75rem' | How far each child travels. Short on purpose: this is a settling, not an entrance from off screen |
| fade | boolean | true | Fades each child in as it settles |
| staggershared | number | 80 | How long after one child the next one starts, in milliseconds. 0 animates the box itself; anything above it moves the effect onto each child in turn |
| durationStepshared | number | 0 | How much longer each successive child takes, in milliseconds. Negative speeds them up down the list, and never past zero |
| reverseshared | boolean | false | Runs the children from the last to the first. Only the order reverses |
| durationshared | number | 420 | How long one run takes, in milliseconds |
| delayshared | number | 0 | How long before it starts, in milliseconds |
| easing | string | — | The easing curve, as CSS writes it. Defaults to the house curve |
| repeatshared | number | 'infinite' | 1 | How many times it runs |
| alternateshared | boolean | false | Runs every other pass backwards, so a repeat returns instead of jumping |
| triggershared | 'mount' | 'visible' | 'hover' | 'manual' | 'mount' | What starts it. visible is on scrolling into view, hover is under the pointer (focus counts), manual is whatever play says |
| play | boolean | — | Runs it when trigger is manual. Each false → true starts it over |
| onceshared | boolean | true | With trigger="visible", whether it runs only the first time. Off, it runs again on every return |
| thresholdshared | number | 0.2 | With trigger="visible", how much of the element has to be on screen, from 0 to 1 |
| pausedshared | boolean | false | Holds the animation where it is |
| render | useRender.RenderProp | — | Renders something other than a div (render={<ul />}). Base UI's own escape hatch |
| children | ReactNode | — | The things that appear, one after another. Each child is one step |
Every other <div> attribute passes through to the root. The settings shared by every Animate* are defined in prop conventions.
The animation is written onto the children themselves rather than onto wrappers around them, so a row of <li>s stays a row of <li>s and a grid's cells stay its direct children. Only a bare string has no element to write onto; that one is wrapped in a <span>.
Examples
stagger
How long after one child the next one starts, in milliseconds. This is the whole effect: everything else is what a single child does.
The stagger is per child, which means what you pass matters: eight children are eight steps, and one child holding eight things is one step. That is also how to opt part of a list out: group it.
from, distance and reverse
from is the edge each child drifts in from and distance is how far: short on purpose, because this is a settling rather than an entrance from off screen. reverse runs the list from the last child to the first.
trigger="visible"
The natural pairing: a block of content that settles in as the reader reaches it, once. The whole set shares one observer on the root, so a list of forty is one observer rather than forty.
Accessibility
- A reduced-motion preference switches the animation off entirely and the whole list is simply there.
- The wrapper adds no role and no name. Give it a real element with
render(render={<ul />}) when the list is a list.