AnimateHeadline
One line replacing the one above it, on a timer. Every line sits in the same grid cell, so the box is as tall as the longest of them from the first frame and never resizes as the reel turns.
import { AnimateHeadline } from 'neba';
<AnimateHeadline interval={2000}>
<span>faster</span>
<span>quieter</span>
<span>yours</span>
</AnimateHeadline>;Props
| Prop | Type | Default | Description |
|---|---|---|---|
| interval | number | 2600 | How long each line is held, in milliseconds. Counted from the moment a line arrives, so it is reading time |
| index | number | — | Which line is showing. Pass it to drive the reel yourself |
| defaultIndex | number | 0 | Where an uncontrolled reel starts |
| onIndexChange | (index: number) => void | — | Called with the line that has just come up |
| loop | boolean | true | Starts again after the last line. Off, the reel stops on the last one |
| rise | number | string | '100%' | How far a line travels as it comes up or leaves. '100%' is one line's own height |
| durationshared | number | 480 | 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' | 'infinite' | 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 |
| children | ReactNode | — | The lines, in the order they should be read |
Every other <div> attribute passes through to the root. The settings shared by every Animate* are defined in prop conventions.
Examples
interval and duration
interval is how long a line is held, counted from the moment it arrives rather than from the start of the cycle, so raising duration, the length of the transition itself, does not quietly eat the reading time.
Controlled
Pass index and the reel stops turning on its own: it becomes a way of moving between lines that something else decides. A step in a form, a tab, a timer of your own. onIndexChange reports the line that has just come up.
loop and rise
loop off stops the reel on the last line and leaves it there. rise is how far a line travels as it comes up or leaves: '100%', the default, is one line's own height, and a smaller value is a nudge rather than a replacement.
<AnimateHeadline loop={false} rise="0.4rem">
<span>Uploading…</span>
<span>Processing…</span>
<span>Done</span>
</AnimateHeadline>Accessibility
- Only the line that is showing is on the accessibility tree; the others are
visibility: hidden, which keeps their space without putting them in the reading order. - Nothing is announced when the reel turns. This is deliberate (a live region cycling every two seconds is unusable), and it is why the component is for a set of phrases where any one of them would have done, not for content a reader has to see.
- A reduced-motion preference drops the transition. The lines still change, they simply arrive rather than slide.