Skip to content

ZStack

ZStack layers child components on top of each other using relative positioning, allowing you to create overlays, badges, floating elements, and complex layered interfaces. Each child is positioned absolutely within the ZStack container.

import { ZStack } from 'rnc-theme';
<ZStack width={200} height={200}>
<Image
source={{ uri: 'profile-image.jpg' }}
style={{ width: '100%', height: '100%' }}
/>
<Box
style={{
position: 'absolute',
bottom: 8,
right: 8,
width: 20,
height: 20,
borderRadius: 10,
backgroundColor: 'green'
}}
/>
</ZStack>

ZStack uses BaseLayoutProps for consistent styling and behavior.

PropTypeDefaultDescription
alignViewStyle['alignItems']'stretch'Default alignment for child positioning
justifyViewStyle['justifyContent']'flex-start'Default justification for child positioning
PropTypeDefaultDescription
childrenReact.ReactNode-Child components to layer
styleStyleProp<ViewStyle>-Additional style properties
paddingkeyof Theme['spacing']-Padding around content
marginkeyof Theme['spacing']-Margin around component
backgroundColorViewStyle['backgroundColor']-Background color
borderRadiuskeyof Theme['components']['borderRadius']-Border radius value
flexnumber-Flex grow/shrink value
widthDimensionValue-Component width (required for proper layering)
heightDimensionValue-Component height (required for proper layering)
themedbooleanfalseEnable theme styles
<ZStack width={80} height={80}>
<Image
source={{ uri: 'user-avatar.jpg' }}
style={{
width: 80,
height: 80,
borderRadius: 40,
position: 'absolute'
}}
/>
<Box
style={{
position: 'absolute',
top: -4,
right: -4,
width: 24,
height: 24,
borderRadius: 12,
backgroundColor: '#ff4444',
borderWidth: 2,
borderColor: 'white'
}}
>
<Center flex={1}>
<Text style={{ color: 'white', fontSize: 12, fontWeight: 'bold' }}>
3
</Text>
</Center>
</Box>
</ZStack>
<ZStack width="100%" height={300}>
<Box
backgroundColor="white"
borderRadius="lg"
padding="lg"
style={{
position: 'absolute',
inset: 0,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 4
}}
>
<VStack spacing="md">
<Text style={{ fontSize: 20, fontWeight: 'bold' }}>
Card Title
</Text>
<Text style={{ color: '#666' }}>
This is the main card content that sits behind the floating action button.
</Text>
</VStack>
</Box>
<Button
title="+"
style={{
position: 'absolute',
bottom: 16,
right: 16,
width: 56,
height: 56,
borderRadius: 28,
backgroundColor: '#2196f3'
}}
/>
</ZStack>
<ZStack width="100%" height={200}>
<Image
source={{ uri: 'hero-background.jpg' }}
style={{
position: 'absolute',
width: '100%',
height: '100%'
}}
resizeMode="cover"
/>
<Box
style={{
position: 'absolute',
inset: 0,
backgroundColor: 'rgba(0,0,0,0.4)'
}}
/>
<Center style={{ position: 'absolute', inset: 0 }}>
<VStack spacing="sm" align="center">
<Text style={{
color: 'white',
fontSize: 28,
fontWeight: 'bold',
textAlign: 'center'
}}>
Welcome to Our App
</Text>
<Text style={{
color: 'white',
fontSize: 16,
textAlign: 'center',
opacity: 0.9
}}>
Discover amazing features
</Text>
</VStack>
</Center>
</ZStack>
const LoadingCard = ({ isLoading, children }) => (
<ZStack width="100%" height={150}>
<Box
backgroundColor="white"
borderRadius="md"
padding="md"
style={{ position: 'absolute', inset: 0 }}
>
{children}
</Box>
{isLoading && (
<Box
style={{
position: 'absolute',
inset: 0,
backgroundColor: 'rgba(255,255,255,0.8)'
}}
>
<Center flex={1}>
<ActivityIndicator size="large" color="#2196f3" />
</Center>
</Box>
)}
</ZStack>
);
<ZStack width={200} height={200} backgroundColor="#f5f5f5">
{/* Top Left */}
<Box
style={{ position: 'absolute', top: 8, left: 8 }}
backgroundColor="red"
width={20}
height={20}
borderRadius="sm"
/>
{/* Top Right */}
<Box
style={{ position: 'absolute', top: 8, right: 8 }}
backgroundColor="blue"
width={20}
height={20}
borderRadius="sm"
/>
{/* Bottom Left */}
<Box
style={{ position: 'absolute', bottom: 8, left: 8 }}
backgroundColor="green"
width={20}
height={20}
borderRadius="sm"
/>
{/* Bottom Right */}
<Box
style={{ position: 'absolute', bottom: 8, right: 8 }}
backgroundColor="orange"
width={20}
height={20}
borderRadius="sm"
/>
</ZStack>
<ZStack width={200} height={200}>
{/* Bottom layer */}
<Box
backgroundColor="#ffcdd2"
style={{
position: 'absolute',
top: 20,
left: 20,
width: 100,
height: 100,
zIndex: 1
}}
/>
{/* Middle layer */}
<Box
backgroundColor="#c8e6c9"
style={{
position: 'absolute',
top: 40,
left: 40,
width: 100,
height: 100,
zIndex: 2
}}
/>
{/* Top layer */}
<Box
backgroundColor="#bbdefb"
style={{
position: 'absolute',
top: 60,
left: 60,
width: 100,
height: 100,
zIndex: 3
}}
/>
</ZStack>

Sizing Guidelines

  • Always provide explicit width and height for proper layering
  • Use percentage-based sizing for responsive overlays
  • Consider using inset for full-coverage overlays

Performance Tips

  • Minimize the number of layers to avoid rendering performance issues
  • Use position: 'absolute' on all child components for proper layering
  • Consider using pointerEvents: 'none' for decorative overlays