1--- 2title: Stacking overlapping views with zIndex in Expo and React Native apps 3sidebar_title: Stack views with zIndex 4description: Learn how to stack overlapping views with zIndex. 5--- 6 7import ImageSpotlight from '~/components/plugins/ImageSpotlight'; 8import SnackEmbed from '~/components/plugins/SnackEmbed'; 9import { Collapsible } from '~/ui/components/Collapsible'; 10 11`zIndex` is the Expo and React Native analog of [CSS's `z-index` property](https://developer.mozilla.org/en-US/docs/Web/CSS/z-index) which lets the developer control the order in which components are displayed over one another. 12 13## Default `zIndex` behavior 14 15Without specifying an explicit `zIndex` or `position`, components that occur later in the tree have a higher z-order. 16 17<SnackEmbed platform="web" preview name="Default layout"> 18 {` 19import React from "react"; 20import { StyleSheet, View } from "react-native";\n 21export default function App() { 22 return ( 23 <View style={styles.root}> 24 <View 25 style={[ 26 styles.container, 27 { 28 backgroundColor: '#e1e4e8', 29 }, 30 ]}> 31 {/* zIndex: 0 */} 32 <View style={[styles.item, { backgroundColor: '#6638f0' }]} /> 33 {/* zIndex: 1 */} 34 <View style={[styles.item, { backgroundColor: '#5cc9f5' }]} /> 35 {/* zIndex: 2 */} 36 <View style={[styles.item, { backgroundColor: '#4af2a1' }]} /> 37 </View> 38 </View> 39 ); 40}\n 41const styles = StyleSheet.create({ 42 root: { 43 flex: 1, 44 backgroundColor: '#fff', 45 alignItems: 'center', 46 justifyContent: 'center', 47 }, 48 container: { 49 height: 200, 50 width: 200, 51 borderRadius: 16, 52 padding: 16, 53 borderWidth: 8, 54 borderColor: 'rgba(0,0,0,0.2)', 55 }, 56 item: { 57 borderWidth: 4, 58 borderColor: 'rgba(0,0,0,0.2)', 59 height: 48, 60 width: 48, 61 borderRadius: 8, 62 }, 63}); 64`} 65</SnackEmbed> 66 67<Collapsible summary="Result"> 68 69<ImageSpotlight 70 style={{ maxWidth: 360 }} 71 alt="Three square components in a square parent container" 72 src="/static/images/z-index/default-layout.png" 73/> 74 75</Collapsible> 76 77This is illustrated more clearly when the components visually intersect each other. 78 79<SnackEmbed platform="web" preview name="Interstecting views"> 80 {` 81import React from "react"; 82import { StyleSheet, View } from "react-native";\n 83export default function App() { 84 return ( 85 <View style={styles.root}> 86 <View 87 style={[ 88 styles.container, 89 { 90 backgroundColor: '#e1e4e8', 91 }, 92 ]}> 93 {/* zIndex: 0 */} 94 <View style={[styles.item, { backgroundColor: '#6638f0' }]} /> 95 {/* zIndex: 1 */} 96 <View style={[styles.item, { backgroundColor: '#5cc9f5', marginTop: -16 }]} /> 97 {/* zIndex: 2 */} 98 <View style={[styles.item, { backgroundColor: '#4af2a1', marginTop: -16 }]} /> 99 </View> 100 </View> 101 ); 102}\n 103const styles = StyleSheet.create({ 104 root: { 105 flex: 1, 106 backgroundColor: '#fff', 107 alignItems: 'center', 108 justifyContent: 'center', 109 }, 110 container: { 111 height: 200, 112 width: 200, 113 borderRadius: 16, 114 padding: 16, 115 borderWidth: 8, 116 borderColor: 'rgba(0,0,0,0.2)', 117 }, 118 item: { 119 borderWidth: 4, 120 borderColor: 'rgba(0,0,0,0.2)', 121 height: 48, 122 width: 48, 123 borderRadius: 8, 124 }, 125}); 126`} 127</SnackEmbed> 128 129<Collapsible summary="Result"> 130 131<ImageSpotlight 132 style={{ maxWidth: 360 }} 133 alt="Three square components intersecting each other" 134 src="/static/images/z-index/default-visually-stacked.png" 135/> 136 137</Collapsible> 138 139## Changing the `zIndex` of an element 140 141If you want to change how a component stacks without changing the order in which it occurs in the component tree, use `zIndex`: 142 143<SnackEmbed platform="web" preview name="zIndex override"> 144 {` 145import React from "react"; 146import { StyleSheet, View } from "react-native";\n 147export default function App() { 148 return ( 149 <View style={styles.root}> 150 <View 151 style={[ 152 styles.container, 153 { 154 backgroundColor: '#e1e4e8', 155 }, 156 ]}> 157 <View style={[styles.item, { backgroundColor: '#6638f0' }]} /> 158 <View style={[styles.item, { backgroundColor: '#5cc9f5', marginTop: -16, zIndex: 1 }]} /> 159 <View style={[styles.item, { backgroundColor: '#4af2a1', marginTop: -16 }]} /> 160 </View> 161 </View> 162 ); 163}\n 164const styles = StyleSheet.create({ 165 root: { 166 flex: 1, 167 backgroundColor: '#fff', 168 alignItems: 'center', 169 justifyContent: 'center', 170 }, 171 container: { 172 height: 200, 173 width: 200, 174 borderRadius: 16, 175 padding: 16, 176 borderWidth: 8, 177 borderColor: 'rgba(0,0,0,0.2)', 178 }, 179 item: { 180 borderWidth: 4, 181 borderColor: 'rgba(0,0,0,0.2)', 182 height: 48, 183 width: 48, 184 borderRadius: 8, 185 }, 186}); 187`} 188</SnackEmbed> 189 190<Collapsible summary="Result"> 191 192<ImageSpotlight 193 style={{ maxWidth: 360 }} 194 alt="Three components where the second is stacked above the first and third" 195 src="/static/images/z-index/relative-z-index.png" 196/> 197 198</Collapsible> 199 200## Manually positioning your component 201 202Along with specifying how the component will stack, you can break out of the default layout set by the component's parent by changing the `position` property on the child component to `'absolute'` and specifying the distance it should be from its parent with the style properties `top`, `right`, `bottom`, and `left`. 203 204<SnackEmbed platform="web" preview name="Position absolute"> 205 {` 206import React from "react"; 207import { StyleSheet, View } from "react-native";\n 208export default function App() { 209 return ( 210 <View style={styles.root}> 211 <View style={[styles.container, { backgroundColor: '#e1e4e8' }]}> 212 <View 213 style={[ 214 styles.item, 215 { backgroundColor: '#6638f0', position: 'absolute', top: 32, left: 32, zIndex: 1 }, 216 ]} 217 /> 218 <View style={[styles.item, { backgroundColor: '#5cc9f5' }]} /> 219 <View style={[styles.item, { backgroundColor: '#4af2a1', marginTop: -16 }]} /> 220 </View> 221 </View> 222 ); 223}\n 224const styles = StyleSheet.create({ 225 root: { 226 flex: 1, 227 backgroundColor: '#fff', 228 alignItems: 'center', 229 justifyContent: 'center', 230 }, 231 container: { 232 height: 200, 233 width: 200, 234 borderRadius: 16, 235 padding: 16, 236 borderWidth: 8, 237 borderColor: 'rgba(0,0,0,0.2)', 238 }, 239 item: { 240 borderWidth: 4, 241 borderColor: 'rgba(0,0,0,0.2)', 242 height: 48, 243 width: 48, 244 borderRadius: 8, 245 }, 246}); 247`} 248</SnackEmbed> 249 250<Collapsible summary="Result"> 251 252<ImageSpotlight 253 style={{ maxWidth: 360 }} 254 alt="Position absolute example" 255 src="/static/images/z-index/absolute-position.png" 256/> 257 258</Collapsible> 259 260You can even make the component extend outside of the parent's visual bounds. 261 262<SnackEmbed platform="web" preview name="Position absolute bounds"> 263 {` 264import React from "react"; 265import { StyleSheet, View } from "react-native";\n 266export default function App() { 267 return ( 268<View style={styles.root}> 269 <View style={[styles.container, { backgroundColor: '#e1e4e8' }]}> 270 <View 271 style={[ 272 styles.item, 273 { backgroundColor: '#6638f0', position: 'absolute', top: -32, left: -32, zIndex: 1 }, 274 ]} 275 /> 276 <View style={[styles.item, { backgroundColor: '#5cc9f5' }]} /> 277 <View style={[styles.item, { backgroundColor: '#4af2a1', marginTop: -16 }]} /> 278 </View> 279 </View> 280 ); 281}\n 282const styles = StyleSheet.create({ 283 root: { 284 flex: 1, 285 backgroundColor: '#fff', 286 alignItems: 'center', 287 justifyContent: 'center', 288 }, 289 container: { 290 height: 200, 291 width: 200, 292 borderRadius: 16, 293 padding: 16, 294 borderWidth: 8, 295 borderColor: 'rgba(0,0,0,0.2)', 296 }, 297 item: { 298 borderWidth: 4, 299 borderColor: 'rgba(0,0,0,0.2)', 300 height: 48, 301 width: 48, 302 borderRadius: 8, 303 }, 304}); 305`} 306</SnackEmbed> 307 308<Collapsible summary="Result"> 309 310<ImageSpotlight 311 style={{ maxWidth: 360 }} 312 alt="Position absolute component out of visual bounds of parent" 313 src="/static/images/z-index/absolute-z-index-bounds.png" 314/> 315 316</Collapsible> 317 318While a `position: 'absolute'` component may seem like it operates independently, it must still respect the `zIndex` of its parent. 319 320<SnackEmbed platform="web" preview name="Parent-child zIndex relationship"> 321 {` 322import React from "react"; 323import { StyleSheet, View } from "react-native";\n 324export default function App() { 325 return ( 326<View style={styles.root}> 327 <View style={[styles.container, { backgroundColor: '#e1e4e8' }]}> 328 <View 329 style={[ 330 styles.item, 331 { backgroundColor: '#6638f0', position: 'absolute', top: -32, left: -32, zIndex: 100 }, 332 ]} 333 /> 334 <View style={[styles.item, { backgroundColor: '#5cc9f5' }]} /> 335 <View style={[styles.item, { backgroundColor: '#4af2a1', marginTop: -16 }]} /> 336 </View> 337 <View style={[styles.container, { backgroundColor: '#dcffe4', marginTop: -188 }]} /> 338 </View> 339 ); 340}\n 341const styles = StyleSheet.create({ 342 root: { 343 flex: 1, 344 backgroundColor: '#fff', 345 alignItems: 'center', 346 justifyContent: 'center', 347 }, 348 container: { 349 height: 200, 350 width: 200, 351 borderRadius: 16, 352 padding: 16, 353 borderWidth: 8, 354 borderColor: 'rgba(0,0,0,0.2)', 355 }, 356 item: { 357 borderWidth: 4, 358 borderColor: 'rgba(0,0,0,0.2)', 359 height: 48, 360 width: 48, 361 borderRadius: 8, 362 }, 363}); 364`} 365</SnackEmbed> 366 367<Collapsible summary="Result"> 368 369<ImageSpotlight 370 style={{ maxWidth: 360 }} 371 alt="Position absolute child must respect parent's zIndex" 372 src="/static/images/z-index/z-index-parent.png" 373/> 374 375</Collapsible> 376