Carousel

The Carousel component displays a series of content in a horizontal scrollable view with optional navigation dots and controls.

npm install @plocks/carousel

Basics

Enable autoPlay and loop on Carousel to rotate a small set of slides without custom pagination controls.

Loading demo…

import { Block, Text } from '@plocks/ui'; import { Carousel } from '@plocks/carousel'; const slides = ['#4C1D95', '#155E75', '#166534']; export function Demo() { return ( <Carousel h={200} loop autoPlay autoPlayInterval={4500} showDots> {slides.map((bg, index) => ( <Block key={bg} bg={bg} radius="lg" h="full" align="center" justify="center"> <Text variant="h3" c="white"> Slide {index + 1} </Text> </Block> ))} </Carousel> ); }

Vertical orientation

Set orientation="vertical" to rotate content along the Y-axis while keeping arrow and dot controls aligned for keyboard and touch users. Vertical carousels size to their container, so give the carousel an explicit h.

Loading demo…

import { Block, Text } from '@plocks/ui'; import { Carousel } from '@plocks/carousel'; const slides = ['#DC2626', '#2563EB', '#0F766E']; export function Demo() { return ( <Carousel orientation="vertical" h={280} loop autoPlay autoPlayInterval={4500} showArrows showDots > {slides.map((bg, index) => ( <Block key={bg} bg={bg} radius="lg" h="full" align="center" justify="center"> <Text variant="h3" c="white"> Slide {index + 1} </Text> </Block> ))} </Carousel> ); }

Image overlay

Layer an absolutely positioned Block with a semi-transparent bg on top of each slide to keep text and buttons readable on photography.

Loading demo…

import { Block, Image, Text } from '@plocks/ui'; import { Carousel } from '@plocks/carousel'; const scenes = [ { title: 'Mountain escape', src: require('../../../../assets/images/scene-mountains.png') }, { title: 'Forest retreat', src: require('../../../../assets/images/scene-forest.png') }, { title: 'Desert journey', src: require('../../../../assets/images/scene-desert.png') }, ]; export function Demo() { return ( <Carousel h={280} loop showArrows showDots> {scenes.map(({ title, src }) => ( <Block key={title} h="full" radius="lg" style={{ overflow: 'hidden' }}> <Image src={src} w="100%" h="100%" resizeMode="cover" /> <Block position="absolute" top={0} right={0} bottom={0} left={0} bg="rgba(15,23,42,0.45)" p="lg" justify="flex-end" > <Text variant="h3" c="white"> {title} </Text> </Block> </Block> ))} </Carousel> ); }

Multiple slides

Combine itemsPerPage with the Embla-style breakpoints prop to show more slides as the viewport grows. Keep slidesToScroll={1} so only one card advances at a time, even when desktop layouts show multiple slides side-by-side.

Loading demo…

import { Block, Text } from '@plocks/ui'; import { Carousel } from '@plocks/carousel'; const slides = ['#1D4ED8', '#0F766E', '#C026D3', '#B45309', '#7C3AED']; export function Demo() { return ( <Carousel h={180} loop showDots slideGap={12} itemsPerPage={1} slidesToScroll={1} breakpoints={{ '@media (min-width: 768px)': { itemsPerPage: 2 }, '@media (min-width: 1200px)': { itemsPerPage: 4 }, }} > {slides.map((bg, index) => ( <Block key={bg} bg={bg} radius="lg" h="full" align="center" justify="center"> <Text variant="h4" c="white"> Slide {index + 1} </Text> </Block> ))} </Carousel> ); }

Performance tuning

Pair windowSize with reducedMotion to keep large or data-heavy carousels responsive while still exposing arrow navigation.

Loading demo…

import { Block, Text } from '@plocks/ui'; import { Carousel } from '@plocks/carousel'; const slides = ['#1E3A8A', '#047857', '#9333EA', '#B91C1C', '#B45309', '#0F766E']; export function Demo() { return ( <Carousel h={180} loop showArrows windowSize={3} reducedMotion slideGap={12}> {slides.map((bg, index) => ( <Block key={bg} bg={bg} radius="lg" h="full" align="center" justify="center"> <Text variant="h4" c="white"> Slide {index + 1} </Text> </Block> ))} </Carousel> ); }

Drag & motion

Tune the interaction model with dragFree, skipSnaps, dragThreshold, and duration to match Embla-style motion control.

Loading demo…

import { Block, Text } from '@plocks/ui'; import { Carousel } from '@plocks/carousel'; function slides(colors: string[]) { return colors.map((bg, index) => ( <Block key={bg} bg={bg} radius="lg" h="full" align="center" justify="center"> <Text variant="h4" c="white"> Slide {index + 1} </Text> </Block> )); } export function Demo() { return ( <Block fullWidth gap="lg"> <Text variant="h5">Free momentum (dragFree)</Text> <Carousel h={160} dragFree itemsPerPage={2} slideGap={12}> {slides(['#0EA5E9', '#6366F1', '#8B5CF6', '#A855F7'])} </Carousel> <Text variant="h5">Locked snaps (skipSnaps off)</Text> <Carousel h={160} itemsPerPage={2} slidesToScroll={1} skipSnaps={false} dragThreshold={45} duration={650} slideGap={12} > {slides(['#F97316', '#EA580C', '#C2410C', '#9A3412'])} </Carousel> </Block> ); }
Scan to open this page on your phoneplocks.dev/carousel/Carousel