skip to content

In React Native, what does the Android-only elevation style do, and why does a card styled only with iOS shadow props look flat on Android?

level: middleimportance: must knowfreq 55%

answer

  1. Android's native elevation API
  2. number in dp, draws a system shadow
  3. also raises z-order among siblings
  4. only shadowColor crosses over, API 28+
  5. boxShadow works on both platforms

basics

~20 s

elevation sets Android's native view elevation, which draws a system shadow and lifts the view above non-elevated siblings. shadowOffset, shadowOpacity and shadowRadius are iOS-only, so on Android only elevation (tinted by shadowColor on API 28+) or boxShadow produces a shadow.

solid answer

~50 s

`elevation` is an Android-only style that sets the native view's elevation, in density-independent pixels. Android then draws its own shadow around the view's outline and also treats the elevated view as higher in the z-order, so it can render above overlapping siblings that come later in the tree. React Native's `shadowOffset`, `shadowOpacity` and `shadowRadius` map to iOS layer properties and do nothing on Android; `shadowColor` is the one shadow prop that works on both, tinting the elevation shadow on Android API 28 and later. So a card with only `shadow*` props has a shadow on iOS and none on Android. The usual answer is `Platform.select` with `shadow*` for iOS and `elevation` for Android, or `boxShadow`, which on the New Architecture renders on both platforms (outset from Android 9). The elevation shadow follows the view's outline, which comes from its background, so a card also needs a `backgroundColor`.

code

tsx · 28 lines
tsx
import { Platform, StyleSheet, Text, View } from 'react-native';

export function QuoteCard({ title }: { title: string }) {
  return (
    <View style={styles.card}>
      <Text>{title}</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  card: {
    backgroundColor: '#ffffff', // the elevation shadow is cast from the background outline
    borderRadius: 8,
    padding: 16,
    shadowColor: '#000000', // iOS shadow colour; tints elevation on Android API 28+
    ...Platform.select({
      ios: {
        shadowOffset: { width: 0, height: 2 },
        shadowOpacity: 0.2,
        shadowRadius: 4,
      },
      android: {
        elevation: 4,
      },
    }),
  },
});

go deeper

for a junior

Recall that elevation is the Android shadow style and that the iOS shadow offset, opacity and radius props are ignored on Android.

for a middle

Explain that elevation sets native elevation, which draws a system shadow and changes z-order, and that shadowColor tints it from API 28.

for a senior

Choose between a per-platform style and boxShadow for a design system, and diagnose overlap bugs caused by elevation's stacking effect.

for a principal

Set the design-system rule for depth: native Material shadows on Android versus one cross-platform boxShadow token, weighed against fidelity and consistency.

## Two shadow systems under one style object React Native has no single shadow model inherited from a web stylesheet. It exposes **platform shadow primitives** plus one cross-platform prop: | Style | iOS | Android | What it maps to | | --- | --- | --- | --- | | `elevation` | ignored | yes | Android's native view elevation | | `shadowColor` | yes | yes, API 28+ | iOS layer shadow color; Android elevation shadow tint | | `shadowOffset`, `shadowOpacity`, `shadowRadius` | yes | ignored | iOS layer shadow properties | | `boxShadow` | yes | yes (outset Android 9+, inset Android 10+) | Spec-style box shadow, New Architecture only | | `filter: dropShadow(...)` | ignored | yes | Alpha-mask drop shadow | The iOS-only props are their own subject; the point here is what Android does with them — **nothing**, except `shadowColor`. ## What `elevation` does `elevation` takes a **number**. React Native converts it from density-independent pixels to physical pixels and sets the native view's elevation. Android then does two things: 1. **Draws a system shadow** under the view. Its size and softness grow with the elevation value, and Android's own lighting model decides the look — you do not choose offset, blur or opacity. 2. **Changes stacking.** A view with higher elevation is drawn above overlapping siblings with lower elevation, even if they come later in the component tree. React Native's docs call this out: elevation "affects z-order for overlapping views". `shadowColor` on API 28 and later sets the colour of that elevation shadow; on older versions it has no effect. ## Why the card looks flat on Android A designer's spec usually arrives as offset, blur and opacity, so the first implementation is: ```tsx const styles = StyleSheet.create({ card: { backgroundColor: '#fff', shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.2, shadowRadius: 4, }, }); ``` On iOS this renders a shadow. On Android three of those four props are ignored, and `shadowColor` only tints an elevation shadow that does not exist yet because `elevation` is unset. Result: a flat card. ## Debugging a missing Android shadow 1. **Is `elevation` set on the view that has the background?** Setting it on a transparent wrapper around the card usually shows nothing. 2. **Is the background opaque?** A transparent or fully see-through `backgroundColor` gives Android no outline to shadow. 3. **Is `shadowColor` fighting you?** From API 28 it tints the elevation shadow; a colour close to the page background makes the shadow look missing. ## Common fixes - **Branch per platform.** Keep the `shadow*` props for iOS and add `elevation` for Android through `Platform.select` inside the style. The two shadows will not be pixel-identical, and that is usually acceptable. - **Use `boxShadow`.** It accepts a web-like string or an array of shadow objects and renders on both platforms under the New Architecture (the only architecture since 0.82). Outset shadows need Android 9+, inset shadows Android 10+. - **Give the view a background.** The elevation shadow is cast from the view's outline, which Android derives from its background; a transparent card typically casts no visible shadow. - **Mind the z-order side effect.** Adding `elevation` to one card can make it overlap a dropdown or badge that used to sit on top. Give the overlay a higher elevation or restructure the tree. ## Units, versions and limits - **Units.** The value is a plain number in density-independent pixels, like other React Native lengths; React Native converts it to physical pixels before handing it to Android. Strings such as `'4dp'` are not accepted. - **Tint.** `shadowColor` is applied to the elevation shadow only on Android 9 (API 28) and later; below that the shadow keeps the system colour. - **Shape control.** You cannot set offset, blur or spread for an elevation shadow. When a design needs those, `boxShadow` is the tool. - **Removing it.** Setting `elevation: 0` removes both the shadow and the raised drawing order. ## Interview summary Say that `elevation` is Android's native elevation — shadow **and** stacking — that the iOS offset/opacity/radius props are ignored on Android while `shadowColor` tints elevation from API 28, and that `boxShadow` is the modern cross-platform option. Mentioning the background requirement and the z-order side effect shows real Android debugging experience.

  • In React Native on Android, why can adding elevation to a card make it cover a dropdown that used to render on top?
    Elevation also raises the view in Android's drawing order: a view with higher elevation is drawn above overlapping siblings with lower elevation, regardless of their order in the tree. Give the dropdown an equal or higher elevation, or move it so it is not a lower-elevation sibling of the card.
  • In React Native, when would you choose boxShadow over a Platform.select of shadow props and elevation?
    When the design needs the same offset, blur and spread on both platforms, or inset or multiple shadows. `boxShadow` renders on iOS and Android under the New Architecture, with outset shadows from Android 9. Elevation stays attractive when a native Material-style shadow is what the design wants.

saying these in an interview costs you the question

  • shadowOffset and shadowRadius work on Android too
  • elevation only draws a shadow and never changes stacking
  • elevation is a string like '4dp'
  • shadowColor has no effect on Android at all
  • boxShadow only works on iOS