# Options

> Set the duration, delay and stagger of scroll reveal animations, choose when an element enters the viewport with threshold and rootMargin, and replay with once.

All the packages accept the same reveal options.

| Option          | Description                                                                                                                        | Default   |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------- | --------- |
| `keyframes`     | The animation. See [Keyframes](/concepts/keyframes/).                                                                              | `slide()` |
| `duration`      | Animation duration, in milliseconds.                                                                                               | `600`     |
| `delay`         | Delay before the animation starts, in milliseconds.                                                                                | `0`       |
| `stagger`       | Animates the element children instead of the element, each one this many milliseconds after the previous one.                      | –         |
| `threshold`     | Fraction of the element, between 0 and 1, that must be visible to reveal it.                                                       | `0`       |
| `rootMargin`    | Grows or shrinks the viewport area that reveals the element, as a CSS margin in `px` or `%`.                                       | `"0px"`   |
| `once`          | Reveals the element only the first time. When `false`, the element hides again when it leaves the viewport.                        | `true`    |
| `when`          | Controls the reveal as a level, so nothing observes the viewport. See [Control the reveal manually](#control-the-reveal-manually). | –         |
| `reducedMotion` | Skips or plays the animation for users who prefer reduced motion. See [Accessibility](/concepts/accessibility/).                   | `"user"`  |

The demos on this page reveal with `slide()`, except the text demo. The `duration` demos show three durations. The other demos play for 1,200 ms, two times the default, so that you can see them better. To play a demo again, select its replay button. When your system reduces motion, the demos do not animate and have no replay button.

`duration: 300`

`duration: 600`

`duration: 1500`

## Stagger

`stagger` animates the element children one after the other. The first child starts after `delay`, and each next child starts `stagger` milliseconds after the previous one:

```jsx
<Reveal as="ul" keyframes={slide()} stagger={80}>
  <li>I enter first...</li>
  <li>...then comes my turn...</li>
  <li>...and finally you see me!</li>
</Reveal>
```

`stagger: 80`

`stagger: 200`

`stagger` animates element children only. It does not animate text nodes. `stagger: 0` animates all the children together.

The library reads the children when the element is revealed. A child that you add before the reveal animates, and a child that you add later does not.

Transforms do not apply to non-replaced inline elements, such as `span` or `a`. Give these children `display: inline-block`. For example, to show a text one character at a time:

```jsx
<p>
  <span className="visually-hidden">{text}</span>
  <Reveal as="span" keyframes={fade()} stagger={30} aria-hidden>
    {[...text].map((char, index) => (
      <span key={index} style={{ display: "inline-block", whiteSpace: "pre" }}>
        {char}
      </span>
    ))}
  </Reveal>
</p>
```

`visually-hidden` is your class that hides content visually, but keeps it for screen readers. Screen readers read the full text one time, and skip the animated characters.

`keyframes: fade(), stagger: 30`

## Viewport

An element is revealed when it enters the viewport:

* With `threshold`, the element must be visible by this fraction. `0.3` reveals the element when 30% of it is visible.
* `rootMargin` changes the viewport area. A negative margin, such as `"0px 0px -100px 0px"`, reveals the element when its top edge is 100px inside the viewport.
* With `once: false`, the element hides again when it leaves the viewport, and the animation plays at each entry.

Two values never reveal an element:

* `threshold: 1` never reveals an element that is taller than the observed area, because the whole element is never inside it. The observed area is the viewport plus `rootMargin`. Use a lower value.
* A negative `rootMargin` shrinks the area that reveals the element. An element at the end of the page, which cannot scroll into that area, never reveals. Add space below the last element, or do not use a negative margin there.

To compare `once`, scroll these demos out of view and back:

`once: true`

`once: false`

## Control the reveal manually

With `when`, your code controls the reveal, and nothing observes the viewport. The element is revealed while `when` is `true`, and hidden while it is `false`. `undefined` and `null` mean that the viewport decides.

* `when` ignores `threshold`, `rootMargin` and `once`.
* With `when: true` at the start, the entrance plays once.
* The server renders an element with `when: true` shown, because nothing hides it. After hydration, the entrance starts at its first keyframe, so the element can flash. To avoid the flash, start with `false` and set `when` to `true` after the first render.

See the framework pages for the syntax: [React](/react/#control-the-reveal-manually), [Vue](/vue/#control-the-reveal-manually) and [Astro](/astro/#control-the-reveal-manually).

## Option changes

A change of `when` applies at once. A change of `threshold`, `rootMargin` or `once` restarts the observation of the viewport. The other options apply at the next reveal. A change does not replay an animation that already played.
