Building a Consistent Styling Workflow for React Native

When Shopify set out to rebuild its package tracking app Arrive into the new Shop digital shopping assistant, every screen needed a complete visual overhaul. The design team introduced a fresh design system, while the engineering side rethought how styling should work across the codebase. The result was Restyle, an open source library guided by several principles that any React Native team can adopt, whether or not they use the library itself.

These best practices answer four recurring questions: how to keep styling consistent across a growing team, how to adapt layouts to different device sizes, how to support dynamic themes such as dark mode, and how to make working with styles less tedious.

Start With a Defined Design System

Consistent styling code starts with a consistent design specification. A design system establishes the rules for how an app should look and feel. Three areas deserve particular attention:

Spacing. While component sizes vary, the spacing between them should remain coherent. Stick to a small set of predefined spacing constants for all margins and paddings. T-shirt sizes (XS, S, M, L, XL) work well because their ordering is intuitive and they scale in both directions.

Color. Separate color definitions into two layers: a literal palette (for example, "Blue," "Light Orange," "Dark Red") and semantic names that describe function ("Primary," "Background," "Danger," "Failure"). Multiple semantic colors may map to the same palette color. Always reference colors through the semantic layer, which simplifies future changes and makes swapping entire color schemes — such as for light and dark mode — straightforward.

Typography. As with spacing, limit the set of font families, weights, and sizes. Group these into named text variants: a "Header" variant might combine a bold weight with size 36 and the Raleway family, while "Body" uses a regular weight, size 16, and Merriweather.

Centralize Values in a Theme Object

Codify the design system as a single theme object. All design values used throughout the app should come from that object so adjustments only require editing one file. Keep the palette private to this definition, exposing only the semantic color names in the theme itself — this enforces the color layering practice at the code level.

Distribute the Theme Through Context

Directly importing the theme into every component limits flexibility. Supporting dark mode would require either importing both themes and deciding per component, or mutating the global values and forcing a full app re-render. Neither is clean.

Supply the theme through React's Context API instead. Components that consume the theme will automatically re-render when the theme changes, and you can override the theme for a sub-tree — for example, giving a profile screen a custom color scheme without affecting the rest of the app.

Expose the Theme Through Components

Reaching into context for style values on every view becomes repetitive. Better to create components that map their props directly to theme values. Two components cover most needs:

  • Box — a View replacement that accepts layout props such as margin, padding, and backgroundColor, restricted to values defined in the theme. For example, margin="m" applies the medium spacing constant, and backgroundColor="primary" applies the semantic primary color.
  • Text — a drop-in replacement for React Native's Text. A variant prop applies the complete set of typographic properties defined in the theme, and a color prop handles text color using the same semantic mapping.

Styling through props instead of separate style sheets initially feels unfamiliar, but it avoids constant jumping between components and stylesheet definitions.

Plan for Multiple Screen Sizes

Responsive design is standard on the web but less common in React Native. Devices vary enough in screen dimensions that one layout does not fit all. An onboarding screen that looks right on a current flagship may feel cramped on a first-generation iPhone SE.

Categorize devices by breakpoints — for instance, anything below 321 pixels wide is a small phone, up to 768 is a regular phone, and anything wider is a tablet. The Box component then accepts props per screen size category, so the required spacing, sizes, and typography adjust to the available space. A complete implementation should fetch current screen dimensions through a hook that refreshes on changes such as device rotation.

Enforce the System With TypeScript

TypeScript validation happens as you write code, unlike React's PropTypes checks that only run at render time. If no type errors are present, no invalid prop values exist anywhere in the app.

Define prop types that accept only values available in the theme. This serves two purposes: your editor flags invalid values, and the autocomplete shows only the valid options as you type. This guidance is especially valuable with the themed Box and Text components, where you can define props that restrict acceptable inputs to the spacing constants, semantic colors, or text variants from your design system.

Putting the Workflow Changes Into Practice

Shopify applied these patterns in its Restyle library, a styling system built for React Native. The practical payoff came quickly: working with styles became noticeably more pleasant. Because the library exposes Box and Text components that constrain color, typography, and spacing options to a defined theme, developers could put together a polished prototype for a new feature before pulling a designer into the loop. Responsive style properties also made it straightforward to adjust a layout for specific screen sizes, which helped the team tailor experiences to individual devices without maintaining separate style branches.

The theming system in Restyle also made a transition between two product identities painless. Shopify kept one theme in place for the Arrive app while iterating on a separate theme for Shop. When the new design was ready to ship, the change was a matter of pointing Restyle at the updated theme object. The same flexibility made dark mode an easy add-on; it wasn't on the roadmap, but the team found it simple enough to implement that they shipped it anyway.

Where to Go From Here

If any of the initial questions about scaling, consistency, or repetitive styling code resonate, the practices outlined above are worth adopting. The Restyle library is available as an open-source project and can serve as a reference implementation for these ideas, helping to make the styling workflow more efficient and more enjoyable.