Skeleton
Animated placeholder for loading content.
Installation
Terminal
npx magic-native-ui@latest add skeletonUsage
The example running in the preview above. Imports use the default aliases from components.json.
skeleton-demo.tsx
import { View } from 'react-native'
import { Skeleton } from '@/components/ui/skeleton'
export function SkeletonDemo() {
return (
<View className="w-full flex-row items-center gap-3">
<Skeleton className="h-12 w-12 rounded-full" />
<View className="flex-1 gap-2">
<Skeleton className="h-4 w-3/4" />
<Skeleton className="h-4 w-1/2" />
</View>
</View>
)
}Component source
What the CLI copies into your project. Once it is there, the code is yours to edit.
registry/ui/skeleton.tsx
import * as React from 'react'
import { Animated, Easing, type ViewProps } from 'react-native'
import { withUniwind } from 'uniwind'
import { cn } from '@/registry/lib/utils'
const AnimatedView = withUniwind(Animated.View)
/**
* `animate-pulse` has no native equivalent, so the pulse is driven by the
* Animated API. The explicit `style` is merged after the class-derived styles,
* so it only controls opacity.
*/
function Skeleton({ className, ...props }: ViewProps) {
const opacity = React.useRef(new Animated.Value(0.5)).current
React.useEffect(() => {
const pulse = Animated.loop(
Animated.sequence([
Animated.timing(opacity, {
toValue: 1,
duration: 800,
easing: Easing.inOut(Easing.ease),
useNativeDriver: true,
}),
Animated.timing(opacity, {
toValue: 0.5,
duration: 800,
easing: Easing.inOut(Easing.ease),
useNativeDriver: true,
}),
])
)
pulse.start()
return () => pulse.stop()
}, [opacity])
return <AnimatedView style={{ opacity }} className={cn('rounded-md bg-muted', className)} {...props} />
}
export { Skeleton }