---
title: "Animation"
description: "Reveal animations, aos / animates-on-scroll, animates-once, animate-disable and child-reveal control."
requested_language: sk
language: en
translation_notice: "This page isn't translated yet"
url: https://docs.systhema.app/sk/styling/animation
version: unreleased (main)
docs_index: https://docs.systhema.app/sk/llms.txt
---
> This page isn't translated yet. Showing English.


Systhema's animation utilities fade content in as it appears: seven fade animations, the `aos` class that holds an element until it scrolls into view, and the classes that decide which elements in a tree reveal on their own.

## Quick reference

<!-- generated:utilities reveal-animations -->

| Class                   | Styles                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `animate-fadein`        | `opacity: 0;`<br>`animation: fadeIn 1s cubic-bezier(0.33, 1, 0.68, 1) forwards;`                                                                                                                                                                                                                                                                                                                                                                                       |
| `animate-fadeinzoomout` | `opacity: 0;`<br>`animation: fadeInZoomOut 1s cubic-bezier(0.33, 1, 0.68, 1) forwards;`                                                                                                                                                                                                                                                                                                                                                                                |
| `animate-fadeinup`      | `opacity: 0;`<br>`animation: fadeInUp 1s cubic-bezier(0.33, 1, 0.68, 1) forwards;`                                                                                                                                                                                                                                                                                                                                                                                     |
| `animate-fadeindown`    | `opacity: 0;`<br>`animation: fadeInDown 1s cubic-bezier(0.33, 1, 0.68, 1) forwards;`                                                                                                                                                                                                                                                                                                                                                                                   |
| `animate-fadeinleft`    | `opacity: 0;`<br>`animation: fadeInLeft 1s cubic-bezier(0.33, 1, 0.68, 1) forwards;`                                                                                                                                                                                                                                                                                                                                                                                   |
| `animate-fadeinright`   | `opacity: 0;`<br>`animation: fadeInRight 1s cubic-bezier(0.33, 1, 0.68, 1) forwards;`                                                                                                                                                                                                                                                                                                                                                                                  |
| `animate-fadeout`       | `opacity: 0;`<br>`animation: fadeOut 1s cubic-bezier(0.33, 1, 0.68, 1) forwards;`                                                                                                                                                                                                                                                                                                                                                                                      |
| `animates-once`         | `animation-iteration-count: 1;`                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `animate-disable`       | `animation: none !important;`                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `animates-on-scroll`    | `&:not(.animated) { animation: none !important; }`<br>`&:not(.animated):not(.animate-disable) { opacity: 0 !important; animation: none !important; }`<br>`@media (prefers-reduced-motion: reduce) { & { opacity: 1 !important; animation: none !important; transform: none !important; } }`<br>`@media (prefers-reduced-motion: reduce) { &:not(.animated):not(.animate-disable) { opacity: 1 !important; animation: none !important; transform: none !important; } }` |
| `aos`                   | `&:not(.animated) { animation: none !important; }`<br>`&:not(.animated):not(.animate-disable) { opacity: 0 !important; animation: none !important; }`<br>`@media (prefers-reduced-motion: reduce) { & { opacity: 1 !important; animation: none !important; transform: none !important; } }`<br>`@media (prefers-reduced-motion: reduce) { &:not(.animated):not(.animate-disable) { opacity: 1 !important; animation: none !important; transform: none !important; } }` |
| `aos-disable-children`  | `& .aos:is(.animated), .aos-disable-children  .aos:not(:is(.animated)), .aos-disable-children  .animates-on-scroll:is(.animated), .aos-disable-children  .animates-on-scroll:not(:is(.animated)) { opacity: 1 !important; animation: none !important; }`                                                                                                                                                                                                               |

<!-- /generated -->

## Basic usage

An `animate-fade*` class plays its animation once, as soon as the element renders: one second, ease-out-cubic, and it stays on its last frame. Press **Replay** to run them again.

```tsx preview iframe height=440 title="Fade animations"
import { useState } from 'react'
import { Button } from '@systhemaui/next'

export default function Demo() {
  const [run, setRun] = useState(0)

  return (
    <div className="flex w-full flex-col items-center gap-6">
      <div key={run} className="grid w-full grid-cols-2 gap-3 md:grid-cols-4">
        <Tile label="fadein" className="animate-fadein" />
        <Tile label="fadeinzoomout" className="animate-fadeinzoomout" />
        <Tile label="fadeinup" className="animate-fadeinup" />
        <Tile label="fadeindown" className="animate-fadeindown" />
        <Tile label="fadeinleft" className="animate-fadeinleft" />
        <Tile label="fadeinright" className="animate-fadeinright" />
        <Tile label="fadeout" className="animate-fadeout" />
      </div>
      <Button.button variant="secondary" onClick={() => setRun(run + 1)}>
        Replay
      </Button.button>
    </div>
  )
}

function Tile({ label, className }: { label: string; className: string }) {
  return (
    <figure className="flex flex-col gap-2">
      <div className="overflow-hidden rounded-lg border border-dashed border-(--color-foundations-surface-border)">
        <div className={`h-16 bg-(--color-foundations-primary-bg) ${className}`} />
      </div>
      <figcaption className="text-small color-label">{label}</figcaption>
    </figure>
  )
}
```

```html
<h2 class="animate-fadeinup">Our services</h2>
```

`animate-fadeinleft` and `animate-fadeinright` start a full element width to the side, so give their container `overflow: hidden` (or `overflow-x-clip` on the section) if the slide must not show outside it.

## Reveal on scroll

On its own, a fade plays at render time, which is usually above or below the fold where nobody sees it. Add `aos` (or the long form `animates-on-scroll`) and the element stays hidden and still until [`AosListener`](https://docs.systhema.app/sk/components/listeners.md#aoslistener) adds the `animated` class as its top edge enters the viewport. Then the fade runs.

```tsx preview iframe height=520 title="Scroll reveal"
import { useState } from 'react'
import { Button } from '@systhemaui/next'

export default function Demo() {
  const [run, setRun] = useState(0)

  return (
    <div className="flex w-full flex-col items-center gap-6">
      <div key={run} className="flex w-full flex-col gap-4">
        <div className="aos animate-fadeinup rounded-lg bg-(--color-foundations-surface-bg) p-6">
          <p className="text-h4 color-heading">Reveals as it scrolls in</p>
          <p className="color-body">aos animate-fadeinup</p>
        </div>
        <div className="aos animate-fadeinup animates-once rounded-lg bg-(--color-foundations-surface-bg) p-6">
          <p className="text-h4 color-heading">Reveals once</p>
          <p className="color-body">aos animate-fadeinup animates-once</p>
        </div>
        <div className="aos-disable-children">
          <div className="aos animate-fadeinup rounded-lg bg-(--color-foundations-surface-bg) p-6">
            <p className="text-h4 color-heading">Shown at once</p>
            <p className="color-body">inside aos-disable-children</p>
          </div>
        </div>
      </div>
      <Button.button variant="secondary" onClick={() => setRun(run + 1)}>
        Replay
      </Button.button>
    </div>
  )
}
```

Scroll this page so the preview leaves the screen and comes back: the first card plays again, the second stays revealed, and the third, inside `aos-disable-children`, never animates.

- `aos` re-arms an element once it has scrolled well below the fold again, so the reveal replays every time the visitor scrolls back down to it.
- `animates-once` keeps the element revealed after the first time.
- `animate-disable` cancels the animation of one element and keeps the listener from revealing it. It does not undo a fade class's starting `opacity: 0`, so an element with both stays hidden: to show it without motion, drop the fade class or wrap it in `aos-disable-children`.
- Without the listener, an `aos` element never gets `animated` and stays invisible, so render `AosListener` once in your root layout. HTML projects get the same engine from the [vanilla JS bundle](https://docs.systhema.app/sk/styling/vanilla-js.md).

The React components add their animation classes from `packages.react.animationClasses` in `systhema.config` (for example `'aos animate-fadeinup'`), and each takes `disableAnimation` to opt out. See [systhema.config reference](https://docs.systhema.app/sk/reference/config.md#packages).

## Child reveals

When a container and its children both reveal, the result looks busy and the children may never be seen settling. So an animating stack, card, hero, column, row, footer, accordion, quote, figure or media overlay cancels every `.aos` / `.animates-on-scroll` reveal anywhere below it: those descendants get `opacity: 1` and no animation, and the container reveals as one unit. The column and row rules apply only while that container animates.

You control this from both sides:

- `aos-disable-children` does the same for any element of yours: everything with `aos` inside it is shown immediately.
- `aos-allow-children` on a `.stack` lets its children keep their own reveals, and `<Stack allowChildAnimation>` adds it for you. It has no effect outside a `.stack`, and it does not override `aos-disable-children` or `animate-disable`.

For every other component, turn the container's animation off (`disableAnimation`) to let child reveals run.

```html
<ul class="aos-disable-children">
  <li class="aos animate-fadeinup">Shown at once, no animation</li>
</ul>
```

## End state

The fades run `forwards`, so their last frame stays applied for the life of the element. That frame ends at `transform: none`, not at an identity such as `translate3d(0, 0, 0)` or `scale(1)`: any other transform would turn the element into a containing block for its `position: absolute` descendants, and an ancestor's `overflow: hidden` would stop clipping them once the element has revealed. Follow the same rule in your own reveal keyframes.

## Reduced motion

Under `prefers-reduced-motion: reduce`, every fade and every `aos` element snaps to its end state: fully visible, no animation, no transform. This is pure CSS, so it holds whether or not the listener runs, and content never stays at `opacity: 0`. Turn on reduced motion in your operating system and the previews above show their final frame immediately. See [Accessibility utilities](https://docs.systhema.app/sk/styling/accessibility.md#reduced-motion).

## Responsive and state variants

The animation classes take variants like any utility: `animate-fadein md:animate-fadeinleft` fades in place on phones and slides in from the side from `md` up.

## Customizing

Delay, duration, easing and stagger are on [Animation timing](https://docs.systhema.app/sk/styling/animation-timing.md). The fade keyframes themselves are part of Systhema's Tailwind config; define your own `@keyframes` and an `--animate-*` theme variable for a new entrance, and add the class next to `aos` to make it scroll-triggered.

## Related

- [Animation timing](https://docs.systhema.app/sk/styling/animation-timing.md)
- [Listeners](https://docs.systhema.app/sk/components/listeners.md)
- [Motion](https://docs.systhema.app/sk/concepts/motion.md)
- [Stack](https://docs.systhema.app/sk/components/stack.md)
