AnimatePresence — slide carousel
Arrow buttons slide a card; exit direction depends on the press.
animate-presence-slides.tsx
import { AnimatePresence, motion, wrap } from 'motion-solidjs'
import { Show, createSignal } from 'solid-js'
export const meta = {
slug: 'animate-presence-slides',
title: 'AnimatePresence — slide carousel',
category: 'animate-presence',
description: 'Arrow buttons slide a card; exit direction depends on the press.',
tag: 'popLayout',
} as const
const colors = ['#ff5d9e', '#ffd166', '#36e0c5', '#7c5cff', '#ff8b3d', '#0cdcf7']
export default function AnimatePresenceSlides() {
const [index, setIndex] = createSignal(0)
const [direction, setDirection] = createSignal<1 | -1>(1)
const slide = (delta: 1 | -1) => {
setDirection(delta)
setIndex((i) => wrap(0, colors.length, i + delta))
}
return (
<div class="flex items-center gap-4">
<button
aria-label="Previous"
onClick={() => slide(-1)}
class="grid h-9 w-9 place-items-center rounded-full border border-border bg-card text-fg-muted hover:text-fg"
>
←
</button>
<div class="relative grid h-24 w-24 place-items-center">
<AnimatePresence mode="popLayout">
<Show when={colors[index()]} keyed>
{(color) => {
const enterFrom = direction() * 60
const exitTo = direction() * -60
return (
<motion.div
class="absolute h-24 w-24 rounded-2xl"
initial={{ opacity: 0, x: enterFrom }}
animate={{
opacity: 1,
x: 0,
transition: {
delay: 0.1,
type: 'spring',
stiffness: 320,
damping: 26,
},
}}
exit={{ opacity: 0, x: exitTo }}
style={{ 'background-color': color }}
/>
)
}}
</Show>
</AnimatePresence>
</div>
<button
aria-label="Next"
onClick={() => slide(1)}
class="grid h-9 w-9 place-items-center rounded-full border border-border bg-card text-fg-muted hover:text-fg"
>
→
</button>
</div>
)
}