A Year of React Native: Styling Part 2

Sam Murray
Made by Many
Published in
5 min readSep 21, 2017
Illustration by Sam Russell Walker

We’ve been using React Native for over a year now and we’re loving how quickly we can create feature-rich and performant apps for iOS and Android. So far we’ve put 4 React Native apps into production. With each project we tried things out and learned lots along the way. We want to share some of that in this series of posts about React Native.

In Part 1 I talked about how styling in React Native is very different from styling on the web. It took us some time to get used to, but after using React Native for a while we’ve seen how its styling concepts provide useful and flexible ways of creating well-structured, extensible apps.

The biggest head-shifts were:

  1. Styles being scoped to components rather than globally across the app
  2. Styles not cascading down to their children
  3. Using JavaScript rather than CSS.

On the web, you might set up some base styles like this:

This would affect all text and text inputs, except those with color rules defined with more specific selectors.

You might also define rules that affect certain classes of DOM element:

There is no equivalent for this in React Native though. Styles can only be passed directly to a component, in the same way that you would pass styles to DOM elements through the style attribute:

This felt like a big constraint at first. We found ourselves repeating lots of styling rules that would only need to be defined once in CSS. But after refactoring and experimenting, we saw how powerful it was to have locally scoped styles that are defined in JavaScript.

There are plenty of modules out there that provide tools and constraints for organising React and React Native applications. Instead of heading straight to npm to choose our favourite, we though we’d explore the possibilities of what we could do just using React Native. These are some of the patterns we’ve found useful.

Illustration by Sam Russell Walker

Mixins

Inspired by CSS preprocessors like SASS, mixins are a great way of keeping your styles DRY and establishing consistency.

Custom components

One method we tried out for sharing styles was to compose React Native components into our own custom set of components. For example, a HeadingText component:

Which can be used like this:

Base style sets

In many cases though, creating custom components just for styling overrides seems like overkill, adding unnecessary complexity to your app.

Another option is to create base styles that can be applied to components when they are used:

Tachyons

In one of our projects, we used a Tachyons-inspired approach to styling. The meant setting up a single global stylesheet that all component definitions would import.

The stylesheet defines a set of styling primitives that are shorthands for a specific set of rules:

The actual file is currently over 600 lines long. Applying styles to a component looks like this:

We found that a big time saver with this pattern was not having to think about the naming of styles. This was particularly noticeable when modifying components. Often even a small change to the way a component works means that the names of styles don’t fit. With a tachyons-style approach, once you get to know the style primitives, modifying the styles of a component is quick and easy.

The downside though is that inevitably there will be some styles you want to apply which can’t be described by your primitives. For example, if a component needs a very specific margin, or the width of a component needs to be a certain proportion of the screen width. These styles are usually best defined within the component definition, rather than adding new styles to the global stylesheet.

Helper functions

Writing styles in JavaScript means you get the power of a programming language rather than a simple styling language. Functions in particular open up a world of possibilities.

Here’s a simple example of how functions helped us implement some responsive styles. Originally, we created a simple method for switching styles based on screen height (we found height to be more useful than width):

But this started to get messy when we wanted to define rules for more than 2 screen sizes:

So we wrote a small function that lets us do this:

Passing context (props, state, etc.) to stylesheets

Similarly, functions helped us to simplify the way we were allowing a component’s styling to adapt to props. In this example, a <Button/> component can be passed colour (string) and disabled (boolean) props, both of which affect it’s style:

Having the prop -> style logic within the component definition felt a bit unclear, so we tried out moving it into the style definition. Instead of returning the stylesheet itself, we return a function that takes props as an argument and returns the stylesheet:

For us, this felt clearer and allowed us to keep styling logic within our stylesheets.

This approach has a downside in terms of optimisation though. When StyleSheet.create is called, React Native sends the styles to the native layer. In the example above, StyleSheet.create is called each time the component renders, which will happen whenever props or state change. This could have a noticeable performance impact if the component needs to re-render frequently, or if lots of instances of <Button/> are instantiated.

Keep experimenting

By trying out different approaches to styling in React Native, we’ve seen how flexible it can be. It has also changed the way we think about how styles could be defined in JavaScript component-based apps, not just in React Native but on the web too.

There are also lots of different libraries to explore: styled-components makes styling a primary constituent of your component definitions; React Native Extended StyleSheet brings lots of the features of CSS to React Native; and Further demonstrates how styling could be composed with functional programming.

We’re going to keep experimenting. We’d love to know what you think about styling in React Native on Twitter @madebymany or @samueljmurray

Made by Many is a new type of consulting company that brings together product design, business strategy and software engineering as a unified discipline. For 10 years we’ve been helping forward-looking companies to re-imagine their customer experiences, create new models for growth and build new capabilities. See our work.

Originally published at madebymany.com.

Illustrations by Sam Russell Walker.

--

--