AniUI

Carousel

Horizontal scrollable carousel with pagination dots and optional auto-play. Uses FlatList for performant scrolling.

Slide 1
Slide 2
Slide 3
import { Carousel } from "@/components/ui/carousel";
<Carousel
  data={[
    <View className="h-48 bg-primary rounded-lg items-center justify-center"><Text className="text-primary-foreground text-lg">Slide 1</Text></View>,
    <View className="h-48 bg-secondary rounded-lg items-center justify-center"><Text className="text-secondary-foreground text-lg">Slide 2</Text></View>,
    <View className="h-48 bg-accent rounded-lg items-center justify-center"><Text className="text-accent-foreground text-lg">Slide 3</Text></View>,
  ]}
/>

Installation

npx @aniui/cli add carousel

Auto-Play

Set autoPlay to automatically cycle through slides. Configure the interval in milliseconds.

Slide 1
Slide 2
Slide 3
<Carousel
  data={slides}
  autoPlay
  interval={3000}
/>

Props

PropTypeDefault
data
ReactNode[]
itemWidth
number
screen width
showDots
boolean
true
autoPlay
boolean
false
interval
number
3000
className
string

Source

components/ui/carousel.tsx
import React, { useRef, useState } from "react";
import { View, FlatList, Dimensions } from "react-native";
import { cn } from "@/lib/utils";

export interface CarouselProps extends React.ComponentPropsWithoutRef<typeof View> {
  className?: string;
  data: React.ReactNode[];
  itemWidth?: number;
  showDots?: boolean;
  autoPlay?: boolean;
  interval?: number;
}
export function Carousel({ className, data, itemWidth, showDots = true, autoPlay, interval = 3000, ...props }: CarouselProps) {
  const [active, setActive] = useState(0);
  const width = itemWidth ?? Dimensions.get("window").width;
  const ref = useRef<FlatList>(null);
  React.useEffect(() => {
    if (!autoPlay || data.length <= 1) return;
    const timer = setInterval(() => {
      const next = (active + 1) % data.length;
      ref.current?.scrollToOffset({ offset: next * width, animated: true });
    }, interval);
    return () => clearInterval(timer);
  }, [autoPlay, active, data.length, interval, width]);
  return (
    <View className={cn("", className)} {...props}>
      <FlatList
        ref={ref}
        data={data}
        horizontal
        pagingEnabled
        showsHorizontalScrollIndicator={false}
        onMomentumScrollEnd={(e) => setActive(Math.round(e.nativeEvent.contentOffset.x / width))}
        renderItem={({ item }) => <View style={{ width }}>{item}</View>}
        keyExtractor={(_, i) => String(i)}
      />
      {showDots && data.length > 1 && (
        <View className="flex-row items-center justify-center gap-1.5 mt-3">
          {data.map((_, i) => (
            <View key={i} className={cn("h-2 rounded-full", i === active ? "w-4 bg-primary" : "w-2 bg-muted-foreground/30")} />
          ))}
        </View>
      )}
    </View>
  );
}