# Animation
**Category**: react
**URL**: https://www.heroui.com/docs/react/getting-started/animation
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/react/getting-started/(handbook)/animation.mdx
> Add smooth animations and transitions to HeroUI v3 components
***
HeroUI components support multiple animation approaches: built-in CSS transitions, custom CSS animations, and JavaScript libraries like Framer Motion.
## Built-in Animations
HeroUI components use data attributes to expose their state for animation:
```css
/* Popover entrance/exit */
.popover[data-entering] {
@apply animate-in zoom-in-90 fade-in-0 duration-200;
}
.popover[data-exiting] {
@apply animate-out zoom-out-95 fade-out duration-150;
}
/* Button press effect */
.button:active,
.button[data-pressed="true"] {
transform: scale(0.97);
}
/* Accordion expansion */
.accordion__panel[aria-hidden="false"] {
@apply h-[var(--panel-height)] opacity-100;
}
```
**State attributes for styling:**
- `[data-hovered="true"]` - Hover state
- `[data-pressed="true"]` - Active/pressed state
- `[data-focus-visible="true"]` - Keyboard focus
- `[data-disabled="true"]` - Disabled state
- `[data-entering]` / `[data-exiting]` - Transition states
- `[aria-expanded="true"]` - Expanded state
## CSS Animations
**Using Tailwind utilities:**
```tsx
// Pulse on hover
// Fade in entrance
Welcome message
// Staggered list
Item 1
Item 2
```
**Custom transitions:**
```css
/* Slower accordion */
.accordion__panel {
@apply transition-all duration-500;
}
/* Bouncy button */
.button:active {
animation: bounce 0.3s;
}
@keyframes bounce {
50% { transform: scale(0.95); }
}
```
## Framer Motion
HeroUI components work seamlessly with Framer Motion for advanced animations.
**Basic usage:**
```tsx
import { motion } from 'framer-motion';
import { Button } from '@heroui/react';
const MotionButton = motion(Button);
Animated Button
```
**Entrance animations:**
```tsx
Welcome!
```
**Layout animations:**
```tsx
import { AnimatePresence, motion } from 'framer-motion';
function Tabs({ items, selected }) {
return (
{items.map((item, i) => (
))}
);
}
```
## Render Props
Apply dynamic animations based on component state:
```tsx
```
## Accessibility
**Respecting motion preferences:** HeroUI automatically respects user motion preferences using Tailwind's `motion-reduce:` utility. All built-in transitions and animations are disabled when users enable "reduce motion" in their system settings.
HeroUI extends Tailwind's `motion-reduce:` variant to support both the native `prefers-reduced-motion` media query and the `data-reduce-motion` attribute.
```css
/* HeroUI pattern - uses Tailwind's motion-reduce: */
.button {
@apply transition-colors motion-reduce:transition-none;
}
/* Expands to support both approaches: */
@media (prefers-reduced-motion: reduce) {
.button {
transition: none;
}
}
[data-reduce-motion="true"] .button {
transition: none;
}
```
With Framer Motion:
```tsx
import { useReducedMotion } from 'framer-motion';
function AnimatedCard() {
const shouldReduceMotion = useReducedMotion();
return (
Content
);
}
```
**Disabling animations globally:** Add `data-reduce-motion="true"` to the `` or `` tag:
```html
```
HeroUI automatically detects the user's `prefers-reduced-motion: reduce` setting and disables animations accordingly.
## Performance Tips
**Use GPU-accelerated properties:** Prefer `transform` and `opacity` for smooth animations:
```css
/* Good - GPU accelerated */
.slide-in {
transform: translateX(-100%);
transition: transform 0.3s;
}
/* Avoid - Triggers layout */
.slide-in {
left: -100%;
transition: left 0.3s;
}
```
**Will-change optimization:** Use `will-change` to optimize animations, but remove it when not animating:
```css
.button {
will-change: transform;
}
.button:not(:hover) {
will-change: auto;
}
```
## Next Steps
- Learn about [Styling](/docs/handbook/styling) approaches
- Explore [Component](/docs/react/components) examples
- View [Theming](/docs/handbook/theming) documentation