Build faster with Premium Chakra UI Components 💎

Learn more
Skip to Content
DocsShowcaseBlogGuides
Sponsor

Animation

Using CSS animations to animate Chakra UI components

AI TipWant to skip the docs? Use our Agent Skills

We recommend using CSS animations to animate your Chakra UI components. This approach is performant, straightforward and provides a lot of flexibility.

You can animate both the mounting and unmounting phases of your components with better control.

Enter animation

When a disclosure component (popover, dialog) is open, the data-state attribute is set to open. This maps to data-state=open and can be styled with _open pseudo prop.

<Box
  data-state="open"
  _open={{
    animation: "fade-in 300ms ease-out",
  }}
>
  This is open
</Box>

Here's an example that uses keyframes to create a fade-in animation:

@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

Exit animation

When a disclosure component (popover, dialog) is closed, the data-state attribute is set to closed. This maps to data-state=closed and can be styled with _closed pseudo prop.

<Box
  data-state="closed"
  _closed={{
    animation: "fadeOut 300ms ease-in",
  }}
>
  This is closed
</Box>

Here's an example that uses keyframes to create a fade-out animation:

@keyframes fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

Composing animations

Use the animationName prop to compose multiple animations together. This makes it easy to create complex animations with multiple keyframes.

<Box
  data-state="open"
  _open={{
    animationName: "fade-in, scale-in",
    animationDuration: "300ms",
  }}
  _closed={{
    animationName: "fade-out, scale-out",
    animationDuration: "120ms",
  }}
>
  This is a composed animation
</Box>

Reduced motion

The built-in component animations play regardless of the user's prefers-reduced-motion setting. To disable the enter/exit animations for users who prefer reduced motion, add this rule to your globalCss config:

import { createSystem, defaultConfig, defineConfig } from "@chakra-ui/react"

const config = defineConfig({
  globalCss: {
    '[data-state="open"], [data-state="closed"]': {
      _motionReduce: {
        animationDuration: "1ms !important",
      },
    },
  },
})

export const system = createSystem(defaultConfig, config)

This collapses the enter/exit animations of every disclosure component (dialog, drawer, menu, popover, tooltip, etc.) to 1ms when reduced motion is enabled.

A few details worth knowing:

  • Scope to data-state="open" and data-state="closed" rather than targeting all elements. A blanket rule also collapses looping animations (Spinner, Skeleton, indeterminate Progress), turning them into a flicker. Loading indicators are considered essential motion and are best left running.
  • animation: none also works. The presence logic detects it and unmounts exiting components immediately. A 1ms duration is suggested because it keeps animationend events firing for any custom code that listens for them.
  • The !important is required because the rule lives in a lower CSS layer than component recipes.

When building custom animations, use the _motionReduce condition to provide a reduced-motion alternative:

<Box
  data-state="open"
  _open={{ animationName: "slide-from-bottom, fade-in" }}
  _motionReduce={{ animationName: "fade-in" }}
>
  Slides on screen, but only fades for reduced motion users
</Box>

Previous

Composition

Next

Color Mode