Skeleton
The Skeleton component provides a placeholder loading state, visually indicating where content will appear once data is fetched. It enhances user experience by managing expectations during loading times.
Installation
$ cbui-cli install skeleton
cbui-cli
globally and authenticated your account. This will ensure you can access all the necessary features.Import
1import { Skeleton } from '@/crossbuildui/skeleton';
2import type { SkeletonSlotsStyles } from '@/crossbuildui/skeleton'; // Optional: for type safety
expo-linear-gradient
for the shimmer effect. Ensure it's installed in your project. If using the isGlass
prop, expo-blur
is also required.Skeleton Component
Basic Usage
Control the visibility of the skeleton or actual content using the isLoaded
prop. The style
prop on the Skeleton component defines the shape and size of the placeholder.
1function MyComponent() {
2 const [isLoaded, setIsLoaded] = useState(false);
3
4 useEffect(() => {
5 // Simulate data fetching
6 const timer = setTimeout(() => setIsLoaded(true), 3000);
7 return () => clearTimeout(timer);
8 }, []);
9
10 return (
11 <View>
12 <Skeleton isLoaded={isLoaded} style={{ width: 200, height: 20, borderRadius: 4, marginBottom: 8 }}>
13 <Text style={{ fontSize: 18, fontWeight: 'bold' }}>Content Loaded!</Text>
14 </Skeleton>
15 <Skeleton isLoaded={isLoaded} style={{ width: '80%', height: 16, borderRadius: 4 }}>
16 <Text>This is some paragraph text that appears after loading.</Text>
17 </Skeleton>
18 </View>
19 );
20}
Custom Shapes and Layouts
Apply styles directly via the style
prop to create various shapes (e.g., circles, specific line heights, image placeholders). You can compose multiple Skeletons to mimic complex layouts.
1<View style={{ gap: 16 }}>
2 {/* Circle Skeleton */}
3 <Skeleton isLoaded={false} style={{ width: 50, height: 50, borderRadius: 25 }}>
4 <Image source={{ uri: 'https://via.placeholder.com/50' }} style={{ width: 50, height: 50, borderRadius: 25 }} />
5 </Skeleton>
6
7 {/* Multiple lines for a text block */}
8 <Skeleton isLoaded={false} style={{ width: '90%', height: 18, borderRadius: 4, marginBottom: 6 }}>
9 <Text style={{ fontSize: 16 }}>A line of text.</Text>
10 </Skeleton>
11 <Skeleton isLoaded={false} style={{ width: '70%', height: 18, borderRadius: 4 }}>
12 <Text style={{ fontSize: 16 }}>Another shorter line.</Text>
13 </Skeleton>
14</View>
Disable Animation
If you prefer a static placeholder without the shimmer animation, set disableAnimation
to true.
1<Skeleton
2 isLoaded={false} /* Keep false to show skeleton */
3 disableAnimation
4 style={{ width: 150, height: 20, borderRadius: 4 }}
5>
6 {/* Content won't be shown as isLoaded is false */}
7</Skeleton>
Custom Colors
Override the default theme-based colors for the placeholder background and shimmer effect using placeholderBackgroundColor
and shimmerColor
props.
1<View style={{ gap: 10 }}>
2 <Skeleton
3 isLoaded={false}
4 style={{ width: '100%', height: 24, borderRadius: 4 }}
5 placeholderBackgroundColor="lightblue"
6 shimmerColor="rgba(200, 200, 255, 0.5)"
7 >
8 {/* Content */}
9 </Skeleton>
10 <Skeleton
11 isLoaded={false}
12 style={{ width: '100%', height: 24, borderRadius: 4 }}
13 placeholderBackgroundColor="#555" // Dark placeholder
14 shimmerColor="rgba(150, 150, 150, 0.3)" // Darker shimmer
15 >
16 {/* Content */}
17 </Skeleton>
18</View>
Glass Effect
Apply a frosted glass effect to the skeleton placeholder using isGlass
. Customize it with glassIntensity
(0-100, this is the base for a pulsing animation) and glassTint
('light'
, 'dark'
, 'default'
). When isGlass
is true, placeholderBackgroundColor
is set to transparent, and the shimmer effect adapts to be more subtle on the blurred background. The glass intensity also has a subtle pulsing animation by default unless disableAnimation
is true.
1<View style={{ gap: 16, padding: 10, backgroundColor: 'rgba(0,0,0,0.2)' /* Darker bg to see light glass */ }}>
2 <Skeleton
3 isLoaded={false} /* Keep false to show skeleton */
4 isGlass
5 glassTint="light"
6 glassIntensity={70} // Base intensity for pulsing animation
7 style={{ width: '90%', height: 20, borderRadius: 4, marginBottom: 8 }}
8 >
9 {/* Content */}
10 </Skeleton>
11 <Skeleton
12 isLoaded={false}
13 isGlass
14 glassTint="dark"
15 glassIntensity={40}
16 style={{ width: '70%', height: 18, borderRadius: 4 }}
17 >
18 {/* Content */}
19 </Skeleton>
20</View>
Props Overview
PROP | TYPE | DEFAULT | DESCRIPTION |
---|---|---|---|
children | ReactNode | - | Actual content to display once loading is complete. |
isLoaded | boolean | false | If true, children are rendered; otherwise, skeleton is shown. |
disableAnimation | boolean | false | If true, shimmer animation is disabled. |
style | StyleProp<ViewStyle> | - | Defines the shape/size of the skeleton placeholder. |
styles | SkeletonSlotsStyles | - | Custom styles for internal slots (placeholder, shimmer). |
shimmerColor | string | Theme-based | Color of the shimmer effect (e.g., 'rgba(255,255,255,0.3)'). |
placeholderBackgroundColor | string | Theme-based | Background color of the placeholder. |
isGlass | boolean | false | Apply glassmorphism effect to the placeholder background. |
glassTint | 'default' | 'light' | 'dark' | Theme-derived | Tint for the glass effect. |
glassIntensity | number | 30 | Base intensity (0-100) for the glass effect's pulsing animation. |
Styling
The primary way to define the skeleton's appearance (shape, size) is through the style
prop. This style is applied to the main placeholder view.
For more granular control, the styles
prop accepts an object with keys for internal slots:
placeholder
: Styles applied to the placeholderView
that contains the shimmer. Thestyle
prop is merged with this. Ensureoverflow: 'hidden'
is maintained if overriding.shimmer
: Styles applied to theAnimated.View
containing theLinearGradient
for the shimmer. This view is absolutely positioned to fill the placeholder. The shimmer effect itself comes from the gradient colors, so direct background styling here might obscure it. WhenisGlass
is true, the shimmer is a more subtle pulsing animation of theBlurView
's intensity rather than a sweeping gradient.
style
prop is crucial as it dictates the dimensions and border radius of the skeleton. The placeholder view has overflow: 'hidden'
by default to correctly clip the sweeping shimmer animation.1<Skeleton
2 isLoaded={false}
3 style={{ width: '100%', height: 40, borderWidth: 2, borderColor: 'blue' }} // Base shape
4 styles={{
5 placeholder: { // Styles for the placeholder View
6 opacity: 0.7,
7 },
8 shimmer: { // Styles for the LinearGradient View
9 // Note: Shimmer effect is achieved by LinearGradient colors,
10 // direct backgroundColor here might cover the gradient.
11 // Use for layout or other non-color style adjustments if needed.
12 }
13 }}
14 placeholderBackgroundColor="lightgreen"
15 shimmerColor="rgba(152, 251, 152, 0.6)"
16>
17 {/* Content */}
18</Skeleton>
Theming
The Skeleton component is theme-aware. By default, placeholderBackgroundColor
and shimmerColor
adapt to the current theme (light/dark mode). If isGlass
is true, placeholderBackgroundColor
is set to transparent.
- Light Mode Default Placeholder:
themeColors.default['100']
- Dark Mode Default Placeholder:
themeColors.default['200']
- Default Shimmer (non-glass): Light mode
'rgba(255, 255, 255, 0.3)'
, Dark mode'rgba(255, 255, 255, 0.1)'
. - Default Shimmer (glass): Light mode
'rgba(0, 0, 0, 0.08)'
, Dark mode'rgba(255, 255, 255, 0.15)'
. This is for the gradient over the blur, though the primary glass animation is intensity pulsing.
You can override these defaults by providing explicit values to the placeholderBackgroundColor
and shimmerColor
props.
Accessibility
Skeletons are primarily visual cues for loading states.
- They don't typically have direct interactive roles or explicit accessibility labels themselves, as their purpose is to represent content that is not yet available.
- Ensure that the surrounding context or a screen reader announcement indicates that content is loading. For example, a page title or a live region update could inform users about the loading state.
- Once content is loaded (
isLoaded=
), ensure the actual content (children
) is fully accessible.