This decade can easily be called the decade of the smartphone. And the numbers are only going up: by 2022 nearly every person on Earth will own one. Mobile has become a great opportunity for nearly every business, but it also comes with a lot of challenges. Android might have a much bigger market share worldwide, but since iOS is more popular with affluent customers, you probably want to cater to both platforms. And let’s not forget the good old web.
What a Time to be Alive
Why We Chose React Native
Let’s be real: React Native doesn’t beat native development when it comes to performance, flexibility or high-end security. It’s a great option when time is the key factor for your project. This was our case when we were asked to build an MVP mobile app (iOS and Android) for a grocery delivery service. Deadline: 2 months.
To make things even harder, we also had to deal with a legacy backend. Preparing APIs for all the app functionalities in this timeframe was simply not possible. This is why React Native seemed even more appealing, as it allowed us to integrate our client’s website views for some parts of the app.
What’s interesting, before making the final decision, we analyzed competitor apps on the market. While there were some pure native solutions out there, most of the analyzed apps use hybrid parts — usually related to renderings of complex, dynamic content, like product catalogues or newsfeeds. Judging from reviews on App and Google Play stores, it seemed that going hybrid wouldn’t affect customer satisfaction.
In the shop’s storefront we implemented both WebView and React Native components.
Brand Design Approach
One of the first big decisions we faced, was to work with platform-agnostic design on both platforms. Giving up on following strict platform’s best practices might sound risky at first but over the years the borders between iOS and Android experiences have become more and more blurry. First of all, many apps decide for the so-called “brand design” approach to establish a unique and unified brand appearance across all channels. This approach also improves the ease of use when users switch between platforms while using a service. Not to mention that material design has been riding a wave of success, with FAB buttons and other Android UI components popping up across many iOS applications. In native development following this approach is expensive and time-consuming. Custom UI always brings in a lot of complexity in terms of implementation, while standard UI components come straight out of the box.
Things look much different in the world of React Native, where the UI is implemented with HTML & CSS. For designers, this actually means a lot of creative freedom without ruining developers’ lives. Our tech team managed to implement the designs almost entirely with our own code coupled with a few small libraries¹.
Having worked on many multi-platform projects before, this usually means A LOT of work for designers especially if you care about consistency. Every time we introduced the smallest of changes to our designs, multiple files had to be updated, then uploaded to multiple projects on Zeplin, and brief members of multiple dev teams. Our workflow in this project was so much easier! We were only designing in one Sketch file (plus the symbol libraries). As the UI was coded using relative units, we only had to maintain one Zeplin project. Our devs didn’t actually use Zeplin to get the assets, instead we exported all icons to a font library for their use. However, Zeplin was still very useful for them as it generated React Native code snippets.
Expectations vs Reality
Since React Native is a promising but still relatively new technology, things won’t always work as expected. This can usually be solved by injecting native code into React, also known as bridges. Airbnb² adopted this hybrid approach, ending up with only 20% functionality left in the RN code.
Airbnb called the bridging process “cumbersome”, and even the official React Native documentation describes it as “a more advanced feature and we don’t expect it to be part of the usual development process, however it is essential that it exists.” In the context of our project (shipping a functional MVP in only 3 months), injecting native code didn’t make sense, as it would have killed all the aspects of speeding up and simplifying our process.
There is no single standardized way to organize navigation between screens. The only two available navigation libraries are still pretty much a work in progress and are infused with bugs. What is effortless on native platforms, becomes really tricky to get right with React. Screen transitions, in particular, come out looking very unnatural in comparison to native experiences.
As for now, it’s best to give up on the idea of applying any shadows in your designs.
On Android, React Native can only customize the elevation parameter of the shadows, as you can imagine the results are far from perfect. Things start to look better on iOS where developers have more control and can tweak colour, opacity or angle. Which brings us to the next point…
Spot the difference — zoom in on the shadows on iOS and Android
Android lags behind
Even though the code in React Native is written only once, it’s rendered differently by the platforms. Unfortunately, for the time being, rendering on Android is much less sophisticated and buggier. The biggest take away for designers is: always remember to review and test the design implementation on different devices, since what works great on iOS might turn out to look like a total mess on Android.
Another technique, next to shadows, is widely used by designers but not supported out of the box by React. After some initial struggle, we managed to implement some basic gradients. Nothing too fancy, but enough to give our app some extra shine and depth.
Usually, designers and developers don’t spend much time thinking about the status bars. We did. Our client’s main brand colour is a very vivid shade of green, which we decided to use as the colour of choice for the navigation bar on selected screens. On more functional views (such as check-out) we applied a lighter, less distracting header. These meant that some of the screens had a dark status bar, while other ones had a light one. Implementing smooth transitions between them turned out to be extremely troublesome. We also encountered issues when displaying dialogs on a semi-transparent background, as they would overlap and practically hide the status bar. Generally speaking, a lot of code tweaking needs to be done to make the status bars behave natively. We’ve proved ourselves that it’s doable, but it did require considerable effort.
Status bars dark & light mode
Last, but not least: WebViews
One of the design challenges we encountered was how to incorporate multiple controls in the app’s navigation skeleton. A big header which shows all the options in a clear way but collapses on scrolling seemed like a perfect solution for this. Unfortunately, it caused a lot of problems when implementing the WebView screens. Since it’s not possible to track exactly the scroll potion in the WebView, the header animation would be out of sync with scrolling. In the end, we decided to stick to the big headers on the home views and implement them natively. On other views, we had to change the header to a regular one.
We had to give up on the idea of an expandable header and come up with a compressed app bar instead
All’s Well That Ends Well
In this post, I’ve tried to map the challenges our design team met when working with React Native. Some of them were very unexpected, some required a few long days & plenty of brainstorming in order to resolve them. Still, in the whole context of the project, none of them prevented our team from reaching our goals. We also have a lot of positive feedback about this technology:
- In an extremely short time, we were able to build a fully functional MVP from scratch. And there’s no bigger pleasure for a designer than seeing your designs implemented and in action.
- React Native is truly great for projects like this: build an MVP, test it in the real world, iterate and move forward. It also allows to gradually replace React elements with native code and further improve the app’s functionalities.
- We delivered a consistent experience for both iOS and Android users. But to achieve this, close collaboration with our dev team and diligent testing is needed.
- React native is a young, but a fast-moving platform. Its strong dev community, backed by Facebook, no less is constantly improving it. So, even though we have encountered some issues, they might be resolved soon.
- Last but not least: React Native provides a great bridge between design and development. Wanna get into your dev’s mindset? Put some hours into learning the basics of coding in RN, especially that the learning curve is much less steep than with other frontend frameworks. Wanna put this knowledge into action? Checkout Framer X.
A huge thank you to Lukasz Czarnecki, Illia Lukanow & Alex Myronov for sharing their React Native knowledge with me and explaining all the technical details for this post.
1: There are of course a lot of React Native UI kits, but they come with very limited styling options. So usually writing custom code makes more sense than reusing them. 2: Airbnb was one of the first major adopters of React Native, a big advocate of its technology and contributor to the developer community. They recently announced sunsetting of RN and moving back to native. We totally recommend their series of Medium posts which give a detailed overview of their experience with React.