React implementation of Stitches CSS-in-JS library with type-safe styling and variants
—
Create CSS animations with keyframes and integrate with theme tokens. The keyframes function generates CSS animations that can be used across styled components and CSS classes.
Creates CSS keyframe animations that can be referenced in styles.
/**
* Creates CSS keyframe animations
* @param styles - Object defining animation keyframes with percentages or keywords
* @returns Keyframes object with name property and toString method
*/
function keyframes(styles: KeyframesObject): KeyframesResult;
interface KeyframesObject {
/** Keyframe percentages (0%, 50%, 100%) or keywords (from, to) */
[percentage: string]: StyleObject;
}
interface KeyframesResult {
/** Returns the animation name for use in CSS */
(): string;
/** CSS animation name */
name: string;
/** String representation of the animation name */
toString(): string;
}Usage Examples:
import { keyframes, styled } from "@stitches/react";
// Basic fade in animation
const fadeIn = keyframes({
'0%': { opacity: 0 },
'100%': { opacity: 1 }
});
// Complex animation with multiple keyframes
const slideAndScale = keyframes({
'0%': {
transform: 'translateX(-100px) scale(0.8)',
opacity: 0
},
'50%': {
transform: 'translateX(0) scale(1.1)',
opacity: 0.8
},
'100%': {
transform: 'translateX(0) scale(1)',
opacity: 1
}
});
// Use in styled components
const AnimatedBox = styled('div', {
animation: `${fadeIn} 0.3s ease-out`
});
const ComplexAnimatedBox = styled('div', {
animation: `${slideAndScale} 0.6s ease-out`
});Combine animations with variant systems for conditional animations.
Usage Examples:
const bounce = keyframes({
'0%, 20%, 53%, 80%, 100%': {
transform: 'translate3d(0, 0, 0)'
},
'40%, 43%': {
transform: 'translate3d(0, -30px, 0)'
},
'70%': {
transform: 'translate3d(0, -15px, 0)'
},
'90%': {
transform: 'translate3d(0, -4px, 0)'
}
});
const pulse = keyframes({
'0%': {
transform: 'scale(1)'
},
'50%': {
transform: 'scale(1.05)'
},
'100%': {
transform: 'scale(1)'
}
});
const AnimatedButton = styled('button', {
padding: '12px 24px',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
variants: {
animation: {
none: {},
bounce: {
animation: `${bounce} 1s ease-in-out`
},
pulse: {
animation: `${pulse} 2s infinite`
},
fadeIn: {
animation: `${fadeIn} 0.3s ease-out`
}
},
loading: {
true: {
animation: `${pulse} 1s infinite`
}
}
}
});
// Usage with animation variants
<AnimatedButton animation="bounce">Bouncy Button</AnimatedButton>
<AnimatedButton loading={true}>Loading Button</AnimatedButton>Use theme tokens within keyframe animations.
Usage Examples:
import { createTheme, keyframes, styled } from "@stitches/react";
const theme = createTheme({
colors: {
primary: 'blue',
secondary: 'lightblue'
},
space: {
sm: '8px',
md: '16px',
lg: '24px'
}
});
// Animations using theme tokens
const colorShift = keyframes({
'0%': {
backgroundColor: '$colors$primary',
transform: 'translateY(0)'
},
'50%': {
backgroundColor: '$colors$secondary',
transform: 'translateY(-$space$md)'
},
'100%': {
backgroundColor: '$colors$primary',
transform: 'translateY(0)'
}
});
const ThemeAnimatedBox = styled('div', {
width: '100px',
height: '100px',
animation: `${colorShift} 2s infinite ease-in-out`
});Create sophisticated multi-step animations with precise timing.
Usage Examples:
// Loading spinner animation
const spin = keyframes({
'0%': { transform: 'rotate(0deg)' },
'100%': { transform: 'rotate(360deg)' }
});
// Morphing animation
const morphing = keyframes({
'0%': {
borderRadius: '50%',
transform: 'scale(1) rotate(0deg)'
},
'25%': {
borderRadius: '25%',
transform: 'scale(1.2) rotate(90deg)'
},
'50%': {
borderRadius: '0%',
transform: 'scale(1.4) rotate(180deg)'
},
'75%': {
borderRadius: '25%',
transform: 'scale(1.2) rotate(270deg)'
},
'100%': {
borderRadius: '50%',
transform: 'scale(1) rotate(360deg)'
}
});
// Typing animation
const typing = keyframes({
'from': { width: '0' },
'to': { width: '100%' }
});
const blink = keyframes({
'0%, 50%': { borderColor: 'transparent' },
'51%, 100%': { borderColor: 'currentColor' }
});
const Spinner = styled('div', {
width: '20px',
height: '20px',
border: '2px solid transparent',
borderTop: '2px solid currentColor',
borderRadius: '50%',
animation: `${spin} 1s linear infinite`
});
const MorphingBox = styled('div', {
width: '50px',
height: '50px',
backgroundColor: 'blue',
animation: `${morphing} 3s infinite ease-in-out`
});
const TypingText = styled('div', {
overflow: 'hidden',
borderRight: '2px solid currentColor',
whiteSpace: 'nowrap',
animation: `
${typing} 3s steps(40, end),
${blink} 0.75s step-end infinite
`
});Control animations based on component state and user interactions.
Usage Examples:
const slideInLeft = keyframes({
from: { transform: 'translateX(-100%)' },
to: { transform: 'translateX(0)' }
});
const slideInRight = keyframes({
from: { transform: 'translateX(100%)' },
to: { transform: 'translateX(0)' }
});
const scaleUp = keyframes({
from: { transform: 'scale(0.5)', opacity: 0 },
to: { transform: 'scale(1)', opacity: 1 }
});
const InteractiveCard = styled('div', {
padding: '20px',
backgroundColor: 'white',
borderRadius: '8px',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
transition: 'transform 0.2s ease',
variants: {
entrance: {
slideLeft: {
animation: `${slideInLeft} 0.5s ease-out`
},
slideRight: {
animation: `${slideInRight} 0.5s ease-out`
},
scale: {
animation: `${scaleUp} 0.3s ease-out`
}
},
hover: {
true: {
'&:hover': {
transform: 'translateY(-4px)'
}
}
}
}
});
// Usage with different entrance animations
<InteractiveCard entrance="slideLeft" hover>
Slides in from left
</InteractiveCard>Combine multiple animations for complex effects.
Usage Examples:
const float = keyframes({
'0%, 100%': { transform: 'translateY(0px)' },
'50%': { transform: 'translateY(-10px)' }
});
const glow = keyframes({
'0%, 100%': { boxShadow: '0 0 5px rgba(59, 130, 246, 0.5)' },
'50%': { boxShadow: '0 0 20px rgba(59, 130, 246, 0.8)' }
});
const rotate = keyframes({
from: { transform: 'rotate(0deg)' },
to: { transform: 'rotate(360deg)' }
});
// Combine multiple animations
const FloatingGlowBox = styled('div', {
width: '100px',
height: '100px',
backgroundColor: 'blue',
borderRadius: '8px',
animation: `
${float} 3s ease-in-out infinite,
${glow} 2s ease-in-out infinite,
${rotate} 10s linear infinite
`
});
// Sequential animations with delays
const SequentialBox = styled('div', {
animation: `
${fadeIn} 0.5s ease-out,
${scaleUp} 0.3s ease-out 0.5s both,
${float} 2s ease-in-out 0.8s infinite
`
});Create animations optimized for performance using transform and opacity.
Usage Examples:
// GPU-accelerated animations
const smoothSlide = keyframes({
from: {
transform: 'translate3d(-100%, 0, 0)',
opacity: 0
},
to: {
transform: 'translate3d(0, 0, 0)',
opacity: 1
}
});
const smoothScale = keyframes({
from: {
transform: 'scale3d(0.8, 0.8, 1)',
opacity: 0
},
to: {
transform: 'scale3d(1, 1, 1)',
opacity: 1
}
});
const PerformantBox = styled('div', {
// Force hardware acceleration
willChange: 'transform, opacity',
backfaceVisibility: 'hidden',
perspective: '1000px',
variants: {
animation: {
slide: {
animation: `${smoothSlide} 0.3s ease-out`
},
scale: {
animation: `${smoothScale} 0.2s ease-out`
}
}
}
});Helper patterns for common animation scenarios.
Usage Examples:
// Staggered animations
const staggeredFade = keyframes({
from: { opacity: 0, transform: 'translateY(20px)' },
to: { opacity: 1, transform: 'translateY(0)' }
});
const StaggeredList = styled('ul', {
'& li': {
animation: `${staggeredFade} 0.5s ease-out both`,
'&:nth-child(1)': { animationDelay: '0s' },
'&:nth-child(2)': { animationDelay: '0.1s' },
'&:nth-child(3)': { animationDelay: '0.2s' },
'&:nth-child(4)': { animationDelay: '0.3s' },
'&:nth-child(5)': { animationDelay: '0.4s' }
}
});
// Infinite loading states
const shimmer = keyframes({
'0%': { transform: 'translateX(-100%)' },
'100%': { transform: 'translateX(100%)' }
});
const LoadingSkeleton = styled('div', {
position: 'relative',
backgroundColor: '#f0f0f0',
overflow: 'hidden',
'&::after': {
content: '""',
position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: 0,
background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.8), transparent)',
animation: `${shimmer} 1.5s infinite`
}
});Install with Tessl CLI
npx tessl i tessl/npm-stitches--react