Remaking a Carousel from Apple's Website
I wanted to recreate this:
Here’s the resulting code and a live preview (best used on desktop). Using Svelte and Tailwind, the recreation experience was surprisingly easy and fun.
It’s not perfect:
- Not pixel perfect
- Doesn’t have a mobile version
- Might be missing some accessibility features
Though there are things it does better than Apple’s:
- The animation does not lock out user input (so you can click the arrow twice quickly)
- It wraps
- The dots at the bottom have bigger hitboxes
The code ended up being much more simple than I thought:
<script>
export let items: { text: string; image: string }[];
let index = 0;
$: index = (index + items.length) % items.length;
</script>
<div class="space-y-5">
<div class="flex items-center justify-center space-x-3">
<button
class="h-12 w-12 rounded-full bg-gray-200 text-lg hover:bg-gray-100"
on:click={() => (index -= 1)}>←</button
>
<div class="flex max-w-xs flex-1 overflow-hidden rounded-3xl bg-gray-50">
{#each items as item}
<div
class="flex w-full flex-shrink-0 flex-col justify-between overflow-hidden transition-transform duration-300"
style:transform="translateX({-100 * index}%)"
>
<p class="flex justify-center px-4 py-14 text-center align-middle">
{item.text}
</p>
<img src={item.image} alt={item.text} />
</div>
{/each}
</div>
<button
class="h-12 w-12 rounded-full bg-gray-200 text-lg hover:bg-gray-100"
on:click={() => (index += 1)}>→</button
>
</div>
<div class="flex items-center justify-center">
{#each items as _, i}
<button class="group flex justify-center p-3 align-middle" on:click={() => (index = i)}>
<div
class="h-2 w-2 rounded-full bg-gray-300 transition-colors"
class:bg-gray-500={i === index}
class:group-hover:bg-gray-400={i !== index}
></div>
</button>
{/each}
</div>
</div>