Carousel
Pre-alphaThe registry and the CLI are not published yet.Roadmap

Carousel

Virtualized carousel driven by data.

Explore

NearbySee all

Installation

npx axiom add carousel
pnpm dlx axiom add carousel
yarn dlx axiom add carousel
bun x axiom add carousel

Installs: react-native-reanimated.

Scrolling, snapping, autoplay and the imperative API live in use-carousel.ts, on top of a virtualized FlatList.

Usage

The API follows the list model: pass data and a render function.

import { Carousel } from "@/components/ui/carousel";

<Carousel
	data={stories}
	renderItem={({ item }) => <StoryCard story={item} />}
	keyExtractor={(item) => item.id}
/>;

Props

PropTypeDefaultDescription
dataT[]Items to render.
renderItem({ item, index, progress }) => ReactElementRenders one item. progress is a shared value from −1 to 1 as the item moves through the center, for scale or parallax effects.
keyExtractor(item: T, index: number) => stringindexStable key per item.
itemWidthnumberscreen width − marginsWidth of each item. Smaller than the viewport, the next item peeks in.
gapSpacingToken3Space between items.
contentInsetSpacingTokenscreenMarginPadding at the start and end, so the first item aligns with the rest of the screen.
snap'item' | 'page' | 'none''item'item stops on each item, page on every visible page, none scrolls freely.
paginationboolean | 'dots' | 'counter'falseIndicator under the carousel: dots, or 2 / 8.
indexnumberControlled active index.
onIndexChange(index: number) => voidCalled when the carousel settles on a new item.
loopbooleanfalseWraps from the last item back to the first.
autoPlaynumberInterval in ms to advance automatically. Paused while the user touches it and when reduce motion is on.
windowSizenumber5Items rendered around the active one. Others are unmounted to keep long carousels light.
refRef<CarouselRef>scrollToIndex(index, animated?), next(), prev().
accessibilityLabelstringNames the carousel for screen readers, such as "Product photos".
styleStyleProp<ViewStyle>Extra styles for the container.

Use cases

Onboarding

Full-width pages with snap="page", dots, and a button that follows the index.

Never miss a train

We’ll ping you when your platform is announced.

Next

const ref = useRef<CarouselRef>(null);
const [index, setIndex] = useState(0);

<Carousel ref={ref} data={slides} snap="page" pagination="dots" onIndexChange={setIndex} renderItem={renderSlide} />
<Button size="lg" fullWidth onPress={() => (index < slides.length - 1 ? ref.current?.next() : finish())}>
  {index < slides.length - 1 ? 'Next' : 'Get started'}
</Button>

Photos with a counter instead of dots when there are many.

3 / 8

Canvas tote
<Carousel
	data={product.photos}
	snap="page"
	pagination="counter"
	renderItem={({ item }) => <Image source={item} style={styles.photo} />}
/>

Stories row

Small round items, free scroll with snap="none", and only nearby items mounted.

Home

<Carousel
	data={stories}
	itemWidth={64}
	gap={3}
	snap="none"
	windowSize={10}
	renderItem={renderStory}
/>

Guidelines

Keep one main scroll direction per area. A horizontal carousel inside a vertical feed is fine; stacking several scroll directions in the same space is not. See Mobile design guidelines.