I have a list of items. When I first load the page, I want them to slide in sequentially in rapid succession and then shrink slightly when they arrive at their final destination — sort of like what would happen if you dropped a stack of pillows, or maybe a giant stack of sliced deli meat. (I’ve seen this animation in the past but I can’t find an example and I have no idea what it’s called; if anyone can find a link to an example, please post it.)
Here’s my highly rudimentary attempt:
import {Button, Slide, Stack, StackProps} from '@mui/material'
import {Box} from '@mui/system'
interface ZoomStackProps extends PropsWithChildren<StackProps> {
timeout: number
}
export default function SquishSlideStack({children, timeout, ...stackProps}: ZoomStackProps) {
const [mountIndex, setMountIndex] = useState(0)
const [squozeIndex, setSquozeIndex] = useState(0)
function increment(n: number) {
if (n < React.Children.count(children) - 1) {
setMountIndex(n)
setTimeout(() => increment(n + 1), timeout)
}
}
useEffect(() => increment(1), [])
return (
<Stack {...stackProps}>
<Button onClick={() => setMountIndex(index => index + 1)}>Next</Button>
{React.Children.map(children, (child, i) =>
i > mountIndex ? (
null
) : (
<Slide
key={i}
in={true}
direction='up'
timeout={1000}
addEndListener={() => setSquozeIndex(i)}
>
<Box bgcolor='green'
width={600}
height={50}
sx={{
transform: i > squozeIndex ? 'scale(1, 1.5)' : 'scale(1, 1)',
transition: 'transform 2s ease'
}}
>
{child}
</Box>
</Slide>
)
)}
</Stack>
)
}
See Codesandbox example.
The sliding part here works, more or less, but only when I leave the squishing/scaling part off. Adding that breaks sliding and also doesn’t scale correctly, for some reason.
What’s the best way to achieve an animation like this in React (and hopefully in MUI, though that’s not required)?
2
Answers
The best way to implement is CSS3 animation.
If you want any help about implementation in React and MUI, please comment.
A simple Demo here, you may need to change parameter about translate3d and scaleY in animation as you like.
To do this, I would use the CSS animations :