
Learn how to build and scale a mobile design system for React Native and native apps to keep your UI consistent and fast.
When I start building a new mobile app for a client, the first few screens always come together quickly. Buttons look great, colors pop, and the layout feels smooth. But by the time we hit fifty screens, things start to drift. A padding here changes from 16 pixels to 12. A button uses a slightly different border radius. The dark mode color on the profile screen doesn't quite match the home screen.
This drift is normal when a product grows, but it hurts user trust and slows down development. That is why building a proper design system is one of the best investments you can make early in a project. In this post, I want to share how I approach designing and implementing mobile UI systems that stay consistent whether you are building with React Native, Expo, or native code.
A mobile design system is more than just a Figma file full of components. It is a single source of truth that bridges the gap between design and code. It includes:
When I built Nept Track, my offline habit tracker and budget app, having a tight system of design tokens saved me hours of tweaking UI elements. Every screen felt like it belonged to the same family because they all pulled from the exact same spacing and color scales.
Before you drop a single button into your codebase, you need to lock down your foundations. On mobile, screen real estate is limited, and touch targets matter much more than on the web.
Use a consistent spacing scale, usually based on a 4-pixel or 8-pixel grid. I typically use a scale like this:
xs: 4pxsm: 8pxmd: 16pxTagged with
Leave a comment
lg: 24pxxl: 32pxxxl: 48pxSticking strictly to these tokens prevents random pixel values like marginRight: 13 from creeping into your stylesheets.
Define a strict type scale with clear hierarchy. On mobile, readability under direct sunlight is a real concern. Ensure your body text is at least 14px to 16px, and line heights are generous.
// theme/typography.ts
export const typography = {
sizes: {
xs: 12,
sm: 14,
md: 16,
lg: 20,
xl: 24,
xxl: 32,
},
weights: {
regular: '400',
medium: '500',
bold: '700',
},
};
Design tokens are the bridge between your Figma designs and your application code. By keeping your tokens in a structured JSON or TypeScript file, you make it easy to support multiple themes, like light and dark mode, without hardcoding hex values everywhere.
Here is a simple example of how I structure color tokens for React Native projects:
// theme/colors.ts
export const lightColors = {
primary: '#2563EB',
background: '#F8FAFC',
surface: '#FFFFFF',
text: '#0F172A',
textMuted: '#64748B',
border: '#E2E8F0',
};
export const darkColors = {
primary: '#3B82F6',
background: '#0F172A',
surface: '#1E293B',
text: '#F8FAFC',
textMuted: '#94A3B8',
border: '#334155',
};
When building the Goldmines Picture App, ensuring smooth switching between light and dark movie discovery themes depended heavily on this token-based approach.
Start small. Build your foundational atoms before tackling complex organisms.
Here is how a clean, reusable button component looks in React Native using our theme tokens:
// components/Button.tsx
import React from 'react';
import { TouchableOpacity, Text, StyleSheet, ActivityIndicator } from 'react-native';
import { lightColors } from '../theme/colors';
interface ButtonProps {
title: string;
onPress: () => sobretudo;
variant?: 'primary' | 'secondary';
loading?: boolean;
}
export const Button = ({ title, onPress, variant = 'primary', loading }: ButtonProps) => {
const isPrimary = variant === 'primary';
return (
<TouchableOpacity
style={[
styles.base,
isPrimary ? styles.primary : styles.secondary,
]}
onPress={onPress}
disabled={loading}
>
{loading ? (
<ActivityIndicator color={isPrimary ? '#FFFFFF' : lightColors.primary} />
) : (
<Text style={[styles.text, isPrimary ? styles.textPrimary : styles.textSecondary]}>
{title}
</Text>
)}
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
base: {
paddingVertical: 14,
paddingHorizontal: 20,
borderRadius: 12,
alignItems: 'center',
justifyContent: 'center',
},
primary: {
backgroundColor: lightColors.primary,
},
secondary: {
backgroundColor: 'transparent',
borderWidth: 1,
borderColor: lightColors.primary,
},
text: {
fontSize: 16,
fontWeight: '600',
},
textPrimary: {
color: '#FFFFFF',
},
textSecondary: {
color: lightColors.primary,
},
});
The biggest challenge with design systems is keeping them updated. When a designer changes a button radius in Figma, how does that make it into the codebase?
For smaller teams, a simple monthly review meeting between design and development works wonders. For larger products, tools like Style Dictionary can automatically convert Figma design tokens exported via JSON into iOS, Android, and web-ready code.
Even without heavy automation, establishing clear naming conventions ensures that a card-radius in Figma translates directly to borderRadius.card in your code.
Scaling a mobile app without a design system is like trying to build a house without blueprints. By investing a little extra time upfront to set up your foundations, tokens, and atomic components, you save countless hours of bug fixes and UI polish down the road.
Need help building a clean, scalable UI for your next mobile app or web product? Get in touch and let's talk about your project.