Animations
CSSX compiles CSS animations and transitions to a format compatible with Reanimated v4. Use standard CSS syntax and apply styles to Reanimated components.
Transitions
Add smooth transitions between state changes:
import { styl } from 'cssxjs'
import Animated from 'react-native-reanimated'
function Tag({ label, active }) {
return (
<Animated.View styleName={['tag', { active }]}>
<Animated.Text styleName={['label', { active }]}>{label}</Animated.Text>
</Animated.View>
)
styl`
.tag
padding 6px 12px
background #e0e0e0
border-radius 16px
transition background 0.2s, transform 0.2s
&.active
background #007bff
transform scale(1.05)
.label
font-size 14px
color #333
transition color 0.2s
&.active
color white
`
}
Transition Syntax
// Single property
transition background 0.2s
// With timing function
transition opacity 300ms ease-out
// With delay
transition transform 0.2s ease 0.1s
// Multiple properties
transition background 0.2s, transform 0.1s, opacity 0.3s
Supported Timing Functions
linear — constant speed from start to finish
ease — starts slow, speeds up, then slows down (default)
ease-in — starts slow and accelerates
ease-out — starts quickly and decelerates
ease-in-out — starts slowly, speeds up, then slows down again
step-start — jumps instantly at the start
step-end — jumps instantly at the end
Keyframe Animations
Define keyframe animations for complex sequences:
import { styl } from 'cssxjs'
import Animated from 'react-native-reanimated'
function FadeIn({ children }) {
return (
<Animated.View styleName="fade-in">
{children}
</Animated.View>
)
styl`
.fade-in
animation fadeIn 500ms ease-out forwards
@keyframes fadeIn
from
opacity 0
transform translateY(-20px)
to
opacity 1
transform translateY(0)
`
}
Keyframe Syntax
Use from/to or percentages:
@keyframes slideIn
from
transform translateX(-100px)
opacity 0
to
transform translateX(0)
opacity 1
@keyframes pulse
0%
transform scale(1)
50%
transform scale(1.1)
100%
transform scale(1)
Animation Properties
The animation shorthand accepts:
animation [name] [duration] [timing] [delay] [iteration] [direction] [fill-mode]
Examples:
// Basic
animation fadeIn 300ms
// With timing and fill mode
animation slideIn 500ms ease-out forwards
// Infinite loop
animation pulse 1s ease-in-out infinite
// Alternate direction (bounce back and forth)
animation bounce 0.5s ease infinite alternate
// With delay
animation fadeIn 300ms ease 100ms
Individual Properties
You can also use individual animation properties:
.element
animation-name fadeIn
animation-duration 500ms
animation-timing-function ease-out
animation-delay 100ms
animation-iteration-count infinite
animation-direction alternate
animation-fill-mode forwards
Using with Reanimated Components
CSSX animations work with Reanimated v4's animated components.
Important: Only use Animated.* components on elements that have animation or transition in their styles. Elements with static styles should use regular React Native components (View, Text, etc.).
import { styl } from 'cssxjs'
import Animated from 'react-native-reanimated'
function AnimatedCard({ visible, children }) {
return (
<Animated.View styleName={['card', { visible }]}>
{children}
</Animated.View>
)
styl`
.card
background white
border-radius 12px
padding 16px
opacity 0
transform translateY(20px)
transition opacity 0.3s, transform 0.3s
&.visible
opacity 1
transform translateY(0)
`
}
With Pressable
Use Reanimated's createAnimatedComponent for interactive elements:
import { useState } from 'react'
import { styl } from 'cssxjs'
import { Pressable, Text } from 'react-native'
import Animated from 'react-native-reanimated'
const AnimatedPressable = Animated.createAnimatedComponent(Pressable)
function AnimatedButton({ onPress, children }) {
const [pressed, setPressed] = useState(false)
return (
<AnimatedPressable
styleName={['button', { pressed }]}
onPressIn={() => setPressed(true)}
onPressOut={() => setPressed(false)}
onPress={onPress}
>
<Text styleName="text">{children}</Text>
</AnimatedPressable>
)
styl`
.button
padding 14px 28px
background #007bff
border-radius 8px
transition transform 0.1s, background 0.2s
&.pressed
transform scale(0.96)
background #0056b3
.text
color white
`
}
Multiple Animations
Apply multiple animations simultaneously:
.element
animation fadeIn 300ms ease, slideIn 500ms ease-out
Both animations run at the same time with their own timing.
Complete Example
A notification toast with enter and exit animations:
import { styl } from 'cssxjs'
import { Pressable, Text } from 'react-native'
import Animated from 'react-native-reanimated'
function Toast({ message, visible, onHide }) {
// Only the outer View needs Animated since it has animation
// Text elements use regular RN components (no animation on them)
return (
<Animated.View styleName={['toast', { visible, hidden: !visible }]}>
<Text styleName="message">{message}</Text>
<Pressable onPress={onHide}>
<Text styleName="close">×</Text>
</Pressable>
</Animated.View>
)
styl`
.toast
position absolute
bottom 20px
align-self center
flex-direction row
align-items center
gap 12px
padding 12px 20px
background #333
border-radius 8px
&.visible
animation slideUp 300ms ease-out forwards
&.hidden
animation slideDown 200ms ease-in forwards
@keyframes slideUp
from
opacity 0
transform translateY(100px)
to
opacity 1
transform translateY(0)
@keyframes slideDown
from
opacity 1
transform translateY(0)
to
opacity 0
transform translateY(100px)
.message
font-size 14px
color white
.close
color white
font-size 18px
padding 0 4px
`
}
How It Works
CSSX compiles animations in a way Reanimated v4 expects:
- Transitions are converted to React Native's transition format with camelCased property names
- Keyframes are inlined directly into the
animationName property as objects
- Timing functions are converted to Reanimated's format
This means you write standard CSS and get native-compatible animations automatically.
Next Steps