Animation » Example Animations » 33. Layout animation

33. Layout animation

Give a motion element a layout property and it will automatically animate when its position (or size) changes.

Code component

The motion.divs are in a grid, which defines their actual position. What makes them change position is the fact that their keys are changed.

The code inside useEffect() runs every time the items array (provided by useCycle()) changes,… which will be every second because that’s when the setTimeout() inside it calls setItems() again.

const itemsA = [1, 2, 3, 4]
const itemsB = [3, 1, 4, 2]
const itemsC = [4, 3, 2, 1]
const itemsD = [2, 4, 1, 3]

const colors = ["#f44", "#3f0", "#fb0", "#0ef"]

export default function CC_33_Layout_animation(props) {
    const [items, setItems] = useCycle(itemsA, itemsB, itemsC, itemsD)

    useEffect(() => {
        setTimeout(() => setItems(), 1000)
    }, [items])

    return (
        <div>
            <div
                style={{
                    display: "grid",
                    gridTemplateColumns: "auto auto",
                    gridGap: 10,
                }}
            >
                {items.map((item) => (
                    <motion.div
                        style={{
                            width: 75,
                            height: 75,
                            borderRadius: 20,
                            backgroundColor: colors[item - 1],
                        }}
                        key={item}
                        layout
                        transition={{
                            type: "spring",
                            stiffness: 350,
                            damping: 25,
                        }}
                    />
                ))}
            </div>
        </div>
    )
}

Code overrides

const positions = [
    { top: 0, left: 0 },
    { top: 0, left: 85 },
    { top: 85, left: 85 },
    { top: 85, left: 0 },
]

const useStore = createStore({ position: 0 })

export function Container(Component): ComponentType {
    return (props) => {
        const [store, setStore] = useStore()

        useEffect(() => {
            setTimeout(() => setStore({ position: store.position + 1 }), 1000)
        }, [store])

        return <Component {...props} />
    }
}

export function Squares(Component): ComponentType {
    return (props) => {
        const { style, name, ...rest } = props

        const [store, setStore] = useStore()

        return (
            <Component
                {...rest}
                layout
                transition={{
                    type: "spring",
                    stiffness: 350,
                    damping: 25,
                }}
                style={{
                    ...style,
                    top: positions[(store.position + Number(name)) % 4].top,
                    left: positions[(store.position + Number(name)) % 4].left,
                }}
            />
        )
    }
}


Join the Framer book mailing list    ( ± 6 emails/year )

GDPR

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing per their Privacy Policy and Terms.



Leave a Reply