Front-end web developers are already comfortable using CSS to make web pages beautiful, and some of the techniques they use will transfer over to helping them build beautiful mobile apps in React Native. But as I’ll show you, a lot of your web-based style thinking will have to be altered to work in the React Native world. RN is a different ecosystem, and as such it requires a number of new approaches to make your app’s presentation layer succinct and tidy.
React Native gives JavaScript developers the power to build beautiful mobile apps while also leveraging their existing JS and CSS knowledge. Reusability and inheritance are two of the major challenges with the way CSS is applied in React Native. In this article I’ll present those challenges in detail, as well as some solutions to them.
Some differences between web-based CSS and React Native styling
Firstly, React Native doesn’t have CSS in the same way the web does. You apply a subset of CSS properties using JSON objects like so:
https://gist.github.com/mcavaliere/0bd71cefc2222f62ec7ea3c3dbb0b3b4
Documentation examples often have these object literals being placed into style objects, which makes things a touch better:
https://gist.github.com/mcavaliere/a519fafb2425edcd4b5e23562c987bb7
Now you’ve got a separation of concerns, at least. And the “markup” (aka the render() method) is much cleaner.
But quite often in real-world projects, we’ll want to have lots of reusable styles to give our app a consistent look and feel. React Native does give us a simple way of simulating CSS “cascading” by applying multiple style objects inside brackets:
https://gist.github.com/mcavaliere/7636e3ea39ab9be98a4e939173e1ae2d
But as you can see, the more modular you get, the faster things get cluttered. Your code starts to become unwieldy, fast.
So now I’ll show you some architectural patterns you can use to make your styles a lot more modular, reusable, and easy to find, without making files like the one above into a complete mess.
A modular approach to React Native styling
The approach we currently use at ATTCK involves a few simple but clever guidelines that achieve a few things:
- separating global styles from those specific to components and screens allowing those global styles to be applied in components and screens, then built upon with more specificity if necessary
- keeping the render() methods from getting cluttered.
Have a style guide
When we create visual designs, we tend to put together visual design palettes first, including colors, typography, and so on. When this happens, those style guidelines should go directly into shared styles for the application.
In our React Native applications, we place these core styles into centrally located files that are structured a lot like SASS or LESS files.
Here’s what a sample project’s file structure looks like:
Inside each file, we define named JavaScript objects that function just like CSS classes:
https://gist.github.com/mcavaliere/86286334b0ae57e095f173e67cbec513
https://gist.github.com/mcavaliere/2795f2b4ba1f9b29407af3dbf1d977de
We export these as constants so we can share them across the app for reusability and style consistency.
Expanding on React Native “cascading”
The concept of cascading styles in RN is nowhere near as flexible as its web counterpart, and when used heavily, it clutters your render() method big-time.
Here’s what a failed attempt at using the RN cascade in a modular way might look like for a simple Card component:
https://gist.github.com/mcavaliere/d00295bc6f8357ce1cbe55eea1f91ef7
Messy, right? It does achieve some level of DRYness by having reusable code in separate modules—Typography, Styles, Colors, and so on. But in order to actually apply those styles to different elements as needed, we fill the style attribute of each element with multiple style objects. This can get out of hand quickly.
An alternative approach to cascading
Our current approach declutters this mess by adding a middle tier. Reusable style objects still go into shared files, but then each component and screen has its own style file in which it maps all of its own styles to any combination of shared styles. It’s a small extra step that goes a long way in keeping things readable.
Typography.js / Color.js / etc. (core styles)
https://gist.github.com/mcavaliere/86286334b0ae57e095f173e67cbec513
Card.style.js (component-specific styles)
https://gist.github.com/mcavaliere/93c41eace7f2519a77e171d0c3b5ece7
Card.js (component)
https://gist.github.com/mcavaliere/45b557afcdd2335f3c766969a9cd1179
Now we’ve got the benefits we seek in a good styling system:
- clean, readable components
- centralized, consistent styles
- an easy way to customize the component or screen as needed.
So this is the approach we’re currently using for styling React Native applications, and it’s given us great benefits in terms of readability, flexibility, and reuse of code. Let us know if you try it out!