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.
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:
// 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.
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.
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.
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:
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.
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.
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:
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,
},
});
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:
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!
The post Applying box shadows in React Native appeared first on LogRocket Blog.