Flavour Carousel
prefers-reduced-motion every change is a cut.FlavourCarousel is built from library pieces: the cart button is Button.Choose your matcha tea
Eight flavours around one cup on a mountain of powder. The ring spins up from behind the powder and settles; then wait five seconds or click a tile: it slides into the cup and the cup's contents change with it. Four tiles on tablets and up, two on phones; switch the site theme to see the tiles go dark. Arrow keys turn the ring when it has focus; hovering holds it.
flavours- are
{ name, price?, tint?, product, tile }in ring order.productis the picture of the product with that flavour inside — cut every one with the same geometry so only the contents change — andtileis what sits on the cream tile.tintcolours the glow behind the product. reveal"in-view"- (the default) plays the entrance the first time the section is on screen; the docs pass
"immediate", and"none"renders the ring in place. Under prefers-reduced-motion the ring is simply there. interval5000- is the rest between turns in milliseconds;
0turns autoplay off and leaves the tiles to the user. onAdd- renders the cart button under the price pill and receives the chosen flavour; leave it out and only the pill remains. The pill shows the
price(the name when there is none) and announces the name to screen readers.onChangereports every turn. foregroundImage- is the powder — a transparent cutout with its peak at the horizontal centre — anchored to the foot of the stage in front of the cup,
foregroundHeight(default0.41) of the stage tall.backgroundImagecovers the section behind everything. Leave both out and the scene is drawn frombackground,mound([light, dark]) andpaper.
Installation
New project? Follow the installation guide to set up Tailwind CSS, shadcn, the cn helper and lucide-react, register the @algorize-ui registry once, then copy your styles from the Themes page.
Install Flavour Carousel
components/ is written into your project. Copy any snippet from a Usage tab above and it runs.
Install dependencies
Step 1 installs this for you. Run it yourself only if you are adding Flavour Carousel to an existing project by hand. The cn helper and lucide-react are not listed — the installation guide covers them once for every component.
button is a component, not a package — the shadcn CLI installs it as source files.
Preparing the pictures
product picture is the same photograph with different contents, cut with identical geometry. If your renders come as one sheet, cut every cell with the same crop box rather than trimming each to its own edges — a shift of even a few pixels reads as the cup jumping. The powder is a separate cutout with a transparent background and its peak at the horizontal centre, so it can stand in front of the cup over a plain backdrop; keep the backdrop free of powder or the two will fight. Transparent WebP keeps each picture under 150 KB.Features
The product never moves
The pictures are stacked and the newest fades in over the one before, so there is no dip, no flicker and no jump — only the contents change.
Springs, and no crossings
Every tile animates to its resting place with a spring, so clicking during a turn redirects the motion instead of restarting it. A far tile is reached step by step at double pace, and a tile remembers which side of the cup it is on: it leaves on that side and comes back in from the other, never across the stage.
One entrance, then it holds still when it should
The ring spins up from behind the powder once, as a single decelerating turn, and hands over to the springs where it stops. After that autoplay pauses while the pointer or focus is on the ring, while the tab is hidden and while the section is scrolled out of view.
Keyboard and screen readers
Tiles are buttons with a pressed state, the arrow keys turn the ring, the tag is a live region and the cart button names the flavour it adds. Reduced motion turns every change into a cut.
Props Reference
| Prop | Type | Default | Description |
|---|---|---|---|
flavours | { name: string; price?: string; tint?: string; product: string; tile: string; alt?: string }[] | — | The flavours in ring order. product is the picture with that flavour inside, tile the ingredient on the tile. |
heading | ReactNode | — | The headline low over the mound. |
initial | number | 0 | The flavour in the cup at the start. |
reveal | "in-view" | "immediate" | "none" | "in-view" | When the entrance plays: the ring rises from behind the powder, spinning, and settles on initial. |
interval | number | 5000 | Milliseconds between turns; 0 turns autoplay off. |
onChange | (index, flavour) => void | — | Called after every turn. |
onAdd, addLabel | (flavour, index) => void, string | —, "Add to cart" | Renders the cart button under the price; the label names it for assistive technology. |
backgroundImage | string | — | The backdrop, covering the section. Without it the ground is drawn. |
backgroundPosition | string | "50% 50%" | object-position for the backdrop. |
foregroundImage | string | — | The powder cutout, anchored to the foot of the stage in front of the cup. |
foregroundHeight | number | 0.41 | The powder's height as a share of the stage; anything wider than the stage is clipped. |
background | string | "#3b4726" | The drawn ground when there is no backdrop. |
mound | [string, string] | ["#7a9550", "#465b2b"] | The drawn powder mound, light and dark. |
paper | string | "#f4f1e7" | The cream of the tiles (light mode), the price pill and the cart. |