Ejiro Asiuwhu Software developer with industry experience in building scalable and performant applications that run on the web and smartphones with cutting-edge technology.

Applying box shadows in React Native

5 min read 1520

Applying Box Shadows In React Native

Applying box shadows in a React Native app is not always straightforward. Because developers must build for both Android and iOS platforms, applying consistent box shadows with different platform-specific implementation processes can be tedious.

In this article, we will learn how to implement box shadows in a React Native app across the Android and iOS platforms.

Using React Native shadow props for iOS box shadows

To create shadow boxes for iOS devices, we can use four React Native shadow props.

The first is shadowColor, which determines the box shadow’s color. Note that this is the only shadow prop that works for Android devices.

The second prop, shadowOffset, accepts objects containing width and height properties with a numerical value:

{ width: number; height: number}

Because it is described by the X and Y offsets relative to the element the box shadow is applied to, the width property determines the X offset of the shadow while the height property determines the Y offset.

Both width and height props can accept positive and negative values.

The third prop is shadowOpacity, which sets the transparency of the box shadow. The prop’s value ranges from 0 to 1, with 0 representing complete transparency and 1 representing complete opacity.

The fourth prop is shadowRadius, which accepts a number as its value to set the blur radius of the component. The larger the value, the larger the blur, marking the shadow bigger and lighter. This prop does not accept negative values.

Let’s use these props by applying a box shadow to a card component with the following:

We made a custom demo for .
No really. Click here to check it out.

// wherever your return statement is   
  <View style={[styles.card, styles.shadowProp]}>
        <View>
          <Text style={styles.heading}>
            React Native Box Shadow (Shadow Props)
          </Text>
        </View>
        <Text>
          Using the elevation style prop to apply box-shadow for iOS devices
        </Text>
      </View>

Next, import StyleSheet to apply multiple styles to the card component:

// remember to import StyleSheet from react-native
const styles = StyleSheet.create({
  heading: {
    fontSize: 18,
    fontWeight: '600',
    marginBottom: 13,
  },
  card: {
    backgroundColor: 'white',
    borderRadius: 8,
    paddingVertical: 45,
    paddingHorizontal: 25,
    width: '100%',
    marginVertical: 10,
  },
  shadowProp: {
    shadowColor: '#171717',
    shadowOffset: {width: -2, height: 4},
    shadowOpacity: 0.2,
    shadowRadius: 3,
  },
});

With the code added, the app renders a card with a box shadow.

iOS Card Renders With A Shadow Box Underneath

Adding the styles.elevation prop for Android

For adding box shadows in Android, we can use the elevation prop, which uses the Android Elevation API.

To learn how to use a box shadow with this method, let’s apply a box shadow to a card component. Note that the styles.elevation prop only works when it is applied to a <View> component:

// wherever your return statement is
<View style={[styles.card, styles.elevation]}>
        <View>
          <Text style={styles.heading}>
            React Native Box Shadow (Elevation)
          </Text>
        </View>
        <Text>
          Using the elevation style prop to apply box-shadow for Android devices
        </Text>
</View>

Next, import the StyleSheet again to style the card:

// remember to import StyleSheet from react-native
const styles = StyleSheet.create({
  heading: {
    fontSize: 18,
    fontWeight: '600',
    marginBottom: 13,
  },
  card: {
    backgroundColor: 'white',
    borderRadius: 8,
    paddingVertical: 45,
    paddingHorizontal: 25,
    width: '100%',
    marginVertical: 10,
  },
  elevation: {
    elevation: 20,
    shadowColor: '#52006A',
  },
});

By setting the elevation to 20 with a shadowColor, we can apply a box shadow to our Android card component.

Android Card Rendered With Shadow Box Underneath

Notice there is no control over the blur radius, opacity, and offset of the box shadow; we only have control over the color of the shadow.

React Native cross-platform box shadow

In this section, we will combine the elevation style props and shadow props to implement box shadows for both Android and iOS devices rather than using two separate processes.

Using the Platform API from React Native, let’s create a function we can later invoke to conditionally render a box shadow for our card component based on a user’s device.

We’ll begin by setting up the card:

 <View style={[styles.card, styles.boxShadow]}>
        <View>
          <Text style={styles.heading}>
            React Native cross-platform box shadow
          </Text>
        </View>
        <Text>Using the Platform API to conditionally render box shadow</Text>
</View>

Next, under our styles object, let’s create the generateBoxShadowStyle function that applies the box shadow based on a user’s operating system:

const generateBoxShadowStyle = (
  xOffset,
  yOffset,
  shadowColorIos,
  shadowOpacity,
  shadowRadius,
  elevation,
  shadowColorAndroid,
) => {
  if (Platform.OS === 'ios') {
    styles.boxShadow = {
      shadowColor: shadowColorIos,
      shadowOffset: {width: xOffset, height: yOffset},
      shadowOpacity,
      shadowRadius,
    };
  } else if (Platform.OS === 'android') {
    styles.boxShadow = {
      elevation,
      shadowColor: shadowColorAndroid,
    };
  }
};

With the code we just implemented, our app can now check the user’s device platform and apply the appropriate box shadow props.

Let’s now invoke the generateBoxShadowStyle function and pass in the value of our shadow and elevation props as arguments:

generateBoxShadowStyle(-2, 4, '#171717', 0.2, 3, 4, '#171717');

It then renders the following to both platforms:

Using The Platform API To Render Shadow Box In Both iOS And Android

To simplify our workflow, use the React Native Shadow Generator tool to generate the code for a box shadow and see a preview of the box shadow on both Android and iOS.

Cross-platform box shadow limitations

While we applied a standard box shadow, there are use cases when we may need full control of the box shadow’s offset, opacity, and blur radius. This can include:

  • Applying a box shadow to a <FlatList> or <Pressable> component with a custom style
  • Adding a custom box shadow design that is consistent across both Andriod and iOS platforms

With the current implementation, this design flexibility is not possible. However, we can overcome these limitations with react-native-drop-shadow.

Applying a box shadow with react-native-drop-shadow

The react-native-drop-shadow package is a View component that takes its nested component, creates a bitmap representation, then blurs and colors it to the style’s shadow values, similar to applying shadows in iOS with the shadow props.

To get started, install the react-native-drop-shadow package using one of the following commands:

yarn add react-native-drop-shadow
#or
npm i react-native-drop-shadow

Once the installation completes, re-sync the Android Gradle build toolkit or restart the development server.

Next, we can import the package:

import DropShadow from "react-native-drop-shadow";

Now, let’s create a custom button using the <Pressable> component and wrap it with the DropShadow component we just imported.

The box shadow on the button in the screenshot below is what we want to create. Notice the consistency in both Android and iOS platforms:

Using React-Native-drop-shadow To Apply Box Shadow Underneath Card In Android And iOS

The DropShadow component is the parent component of our <Pressable> component, which we styled to look like a button. We want it in this order because we want to apply the drop shadow to our button and not the text in the button:

// wherever your return statement is
// Don't forget to import the Pressable component from react-native
<DropShadow style={styles.shadowProp}>
          <Pressable
            style={styles.button}
            onPress={() => console.log('pressed')}>
            <Text style={(styles.text, styles.buttonText)}>See more</Text>
          </Pressable>
</DropShadow>

To make our <Pressable> component look like a button and add the drop shadow to the DropShadow component, add the following stylesheet:

const styles = StyleSheet.create({
shadowProp: {
    shadowColor: '#171717',
    shadowOffset: {width: 0, height: 3},
    shadowOpacity: 0.4,
    shadowRadius: 2,
  },
  button: {
    backgroundColor: '#4830D3',
    alignItems: 'center',
    justifyContent: 'center',
    height: 42,
    borderRadius: 4,
    marginTop: 30,
  },
  buttonText: {
    color: '#fff',
  },
  text: {
    fontSize: 16,
    lineHeight: 21,
    fontWeight: 'bold',
    letterSpacing: 0.25,
  },
});

Using react-native-shadow-2

The react-native-shadow-2 package is an improved version of react-native-shadow by providing more functionalities, Typescript support, and written from scratch to reduce dependencies that affect performance.

Unlike implementing a drop shadow with react-native-drop-shadow, which creates a bitmap representation of its child components, react-native-shadow-2 uses the react-native-svg shadow plugin for consistent implementation across the Android and iOS platforms.

To get started, install both of these packages in the project directory root:

yarn add react-native-svg react-native-shadow-2
#or 
npm i react-native-svg react-native-shadow-2

To ensure this runs on iOS, CD into the ios directory and run pod install to sync the packages we just installed:

// import the package right at the top
import {Shadow} from 'react-native-shadow-2';

// wherever your return statement is
<Shadow
        distance={5}
        startColor={'#00000010'}
        containerViewStyle={{marginVertical: 20}}
        radius={8}>
        <View style={[styles.card, {marginVertical: 0}]}>
          <View>
            <Text style={styles.heading}>
              React Native cross-platform box shadow
            </Text>
          </View>
          <Text style={styles.boxShadow}>
            Using the Platform API to conditionally render box shadow
          </Text>
          <DropShadow style={styles.shadowProp}>
            <Pressable
              style={styles.button}
              onPress={() => console.log('pressed')}>
              <Text style={(styles.text, styles.buttonText)}>See more</Text>
            </Pressable>
          </DropShadow>
        </View>
      </Shadow>

The code produces the following:

Using React-Native-Shadow-2 To Apply Box Shadow Underneath A Card In iOS and Android

Conclusion

The major problem with shadow props in React Native is that they cannot be used in Android applications.

However, by using react-native-drop-shadow and react-native-shadow-2, we can easily implement consistent box shadows into our React Native apps for both Android and iOS platforms.

The full code used in this tutorial is available on GitHub. Feel free to drop a comment to let me know what you thought of this article. You can also find me on Twitter and GitHub. Thank you for reading!

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Ejiro Asiuwhu Software developer with industry experience in building scalable and performant applications that run on the web and smartphones with cutting-edge technology.

Leave a Reply