Creating a responsive design system for React Native Web and mobile

Kheva Mann
Bootcamp
Published in
3 min readNov 23, 2021

--

Photo by Domenico Loia on Unsplash

Creating a multiplatform app has become easier than ever with the introduction of React Native and React Native Web which has made it possible to create one codebase for iOS, Android and web. While this sounds great (and is) it means that your code is now supporting devices ranging from smartphones and tablets to desktops and TVs. With all these different screen sizes, it is important to make sure your UI is responsive and renders beautifully on every device.

React Native provides methods to create responsive designs that get the job done, but they all lead to very cluttered code. For example, the code below can be used to create a dynamic style based on the device size.

const isSmallDevice = Dimensions.get('window').width < 768<View style={[styles.box, isSmallDevice && {/*Mobile styles*/}]}>

This is fine when there are only a few styles, however as the complexity of the components grow, the second line must be repeated everywhere and the code becomes harder to read.

The Solution

I wanted a cleaner way to define responsive styles throughout our React Native Web codebase. I decided the best approach would be to create a helper that will build a stylesheet for web, and an additional one for styles that will be overridden on mobile. This helper needs to be called globally in the file as React Native StyleSheet performs some optimizations so that it only creates styles once and they are never re-updated. This means there are less trips across the JS-Native bridge, which are very expensive.

In the above code I am creating web and mobile override stylesheets then returning a helper that wraps these styles. This helper is a nested closure so that it can be called inside a component to initialize the styles with the appropriate device size.

Below is an example implementing the responsive StyleSheet. Notice how it is defined just like a regular StyleSheet outside any components. Then on line 8 we initialize the styles with the device size. This allows us to call each style directly through the initialized function (line 11).

Why are we usinguseWindowDimensions()?

React Native provides us with the Dimensions API to get the device size, however there is nothing that will tell us if there is a change to the device size. So changing a device’s orientation or window size will cause the UI to become unusable. React Native 0.61 provides the useWindowDimensions() hook to allow for automatic re-rendering when the layout changes. Therefore we can pass that into our styles to create a dynamic style based on the actual size.

Results

Below are the results of the FeatureCard.tsx file above. On large devices, it spans the whole page and has the text to the left, and on mobile the text is below the image.

web version of responsive card with image to the right of the text
Responsive Card on large devices
mobile version of responsive card with image above text
Responsive Card on small devices

Variations

It is important to note that this is using a web first approach to responsive design. To use a native first approach, the parameters to the function can be swapped and the condition can be layout.width > 768 or any cutoff number.

If there is not a concern of the device size changing outside a render, then the function can just use the Dimensions API and does not need the secondary initialization inside the component.

Responsive Styles NPM Package

I built a package based on the above discussion, it provides a performant way of styling based on device size, you can check it out here.

https://www.npmjs.com/package/rn-responsive-styles

--

--