AniUI

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 skeleton

This 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
className
string

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}
    />
  );
}