Skeleton
Animated loading placeholder with pulse effect.
import { Skeleton } from "@/components/ui/skeleton";
export function MyScreen() {
return (
<View className="space-y-3">
<Skeleton className="h-4 w-48" />
<Skeleton className="h-4 w-32" />
<Skeleton className="h-10 w-10 rounded-full" />
</View>
);
}Installation
npx @aniui/cli add skeletonThis component requires react-native-reanimated for the pulse animation.
Usage
app/index.tsx
import { Skeleton } from "@/components/ui/skeleton";
export function MyScreen() {
return (
<View className="space-y-3">
<Skeleton className="h-4 w-48" />
<Skeleton className="h-4 w-32" />
<Skeleton className="h-10 w-10 rounded-full" />
</View>
);
}Props
PropTypeDefault
classNamestring—Also accepts all View props from React Native. Use className to set width, height, and border radius.
Source
components/ui/skeleton.tsx
import React, { useEffect } from "react";
import { View } from "react-native";
import Animated, {
useSharedValue,
useAnimatedStyle,
withRepeat,
withSequence,
withTiming,
} from "react-native-reanimated";
import { cn } from "@/lib/utils";
export interface SkeletonProps extends React.ComponentPropsWithoutRef<typeof View> {
className?: string;
}
export function Skeleton({ className, ...props }: SkeletonProps) {
const opacity = useSharedValue(1);
useEffect(() => {
opacity.value = withRepeat(
withSequence(
withTiming(0.4, { duration: 800 }),
withTiming(1, { duration: 800 })
),
-1,
false
);
}, [opacity]);
const animatedStyle = useAnimatedStyle(() => ({
opacity: opacity.value,
}));
return (
<Animated.View
className={cn("rounded-md bg-muted", className)}
style={animatedStyle}
{...props}
/>
);
}