Skip to main content
RNTutorials
Malik Chohra

By Malik Chohra

The Complete React Native Design System Guide with Restyle (2026)

Build a type-safe, themeable design system in React Native with Shopify's Restyle: theme tokens, Box/Text primitives, a reusable component library, dark mode, and responsive variants.

Building a Type-Safe Design System with Restyle

Shopify's Restyle library gives React Native a powerful, type-safe way to build a design system. Instead of scattering inline styles and hardcoded hex values across every screen, you define your design tokens once and let TypeScript enforce them at compile time. The result is consistent styling that scales across a large app and is far easier to refactor.

This is the complete guide: it covers the theme, the core primitives, a reusable component library built on atomic design principles, full dark and light mode support, and responsive variants. By the end you'll have a production-ready foundation you can drop into any React Native or Expo project.

Why Choose Restyle?

  • Type Safety - Full TypeScript support with compile-time checking. You can only reference colors, spacing, and variants that actually exist in your theme.
  • Themeable - A built-in theme system makes dark/light switching and rebranding a single source change.
  • Consistent API - One unified styling approach across every component, so the whole team writes UI the same way.
  • Performance - Style resolution is memoized, so there is no meaningful runtime cost over plain StyleSheet usage.

Step 1: Creating Your Theme

The foundation of any Restyle design system is a well-structured theme. Define your colors, spacing, typography, and other design tokens in a single centralized object. Everything downstream reads from this file, so changing your brand color or base spacing scale is a one-line edit.

// theme.ts
import { createTheme } from '@shopify/restyle';

const theme = createTheme({
  colors: {
    primary: '#007AFF',
    secondary: '#5856D6',
    background: '#FFFFFF',
    cardBackground: '#F2F2F7',
    text: '#000000',
  },
  spacing: {
    s: 8,
    m: 16,
    l: 24,
    xl: 40,
  },
  borderRadii: {
    s: 4,
    m: 8,
    l: 16,
  },
  breakpoints: {
    phone: 0,
    tablet: 768,
  },
});

export type Theme = typeof theme;
export default theme;

Step 2: Core Primitives (Box and Text)

Restyle's Box and Text components are the building blocks for everything else. They give you a consistent, type-safe API for styling, the props you pass (like padding="m" or backgroundColor="primary") are validated against your theme.

// primitives.tsx
import { createBox, createText } from '@shopify/restyle';
import { Theme } from './theme';

export const Box = createBox<Theme>();
export const Text = createText<Theme>();

// Usage
<Box padding="m" backgroundColor="primary">
  <Text variant="header" color="background">
    Hello Restyle!
  </Text>
</Box>

Step 3: A Reusable Component Library (Atomic Design)

With your theme and primitives in place, build a library of reusable components. Organizing it with atomic design methodology keeps the structure predictable as the app grows:

  • Atoms - Basic building blocks (Box, Text, Button)
  • Molecules - Simple combinations (InputField, Card)
  • Organisms - Complex components (Form, Modal)
  • Templates - Page-level layout structures

Variants are the key to reusable components. Define button styles once in the theme, then reference them by name:

// Button.tsx
import { createRestyleComponent, createVariant, VariantProps } from '@shopify/restyle';
import { Pressable, PressableProps } from 'react-native';
import { Theme } from './theme';

const buttonVariant = createVariant({ themeKey: 'buttonVariants' });

export const Button = createRestyleComponent<
  VariantProps<Theme, 'buttonVariants'> & PressableProps,
  Theme
>([buttonVariant], Pressable);

// Usage
<Button variant="primary" onPress={handlePress}>
  <Text>Click Me</Text>
</Button>

A reusable Card is just as concise, it reads its background, radius, and shadow straight from the theme, so every card in the app stays visually identical:

// Card.tsx
export const Card = ({ children }) => (
  <Box
    backgroundColor="cardBackground"
    borderRadius="m"
    padding="m"
    shadowColor="text"
    shadowOffset={{ width: 0, height: 2 }}
    shadowOpacity={0.1}
    shadowRadius={4}
  >
    {children}
  </Box>
);

Step 4: Dark and Light Mode

Dark mode is now an expected feature, not a nice-to-have. Restyle makes it straightforward: define a light theme and a dark theme with the same shape but different color values, then swap the theme passed to ThemeProvider. Because every component reads semantic color names rather than literal hex values, nothing else has to change.

// themes.ts
export const lightTheme = createTheme({
  colors: {
    background: '#FFFFFF',
    text: '#000000',
    primary: '#007AFF',
    cardBackground: '#F2F2F7',
  },
  spacing: { s: 8, m: 16, l: 24, xl: 40 },
  borderRadii: { s: 4, m: 8, l: 16 },
  breakpoints: { phone: 0, tablet: 768 },
});

export const darkTheme: typeof lightTheme = {
  ...lightTheme,
  colors: {
    ...lightTheme.colors,
    background: '#000000',
    text: '#FFFFFF',
    primary: '#0A84FF',
    cardBackground: '#1C1C1E',
  },
};

Wire it to the system color scheme and remember the user's choice. useColorScheme() picks up the device setting, and persisting the preference (for example with AsyncStorage) keeps it stable across app launches:

// ThemeContext.tsx
import { ThemeProvider } from '@shopify/restyle';
import { useColorScheme } from 'react-native';
import { lightTheme, darkTheme } from './themes';

export const AppThemeProvider = ({ children }) => {
  const scheme = useColorScheme();
  const theme = scheme === 'dark' ? darkTheme : lightTheme;
  return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
};

A few rules keep theming reliable: test every component in both modes, use semantic color names instead of literal colors, keep contrast high enough for accessibility, and add smooth transitions so the switch never feels abrupt.

Step 5: Responsive Variants

Restyle's breakpoint system lets a single component adapt to phones and tablets without duplicating layouts. Pass an object keyed by breakpoint and Restyle resolves the right value for the current screen width:

<Box
  flexDirection={{ phone: 'column', tablet: 'row' }}
  padding={{ phone: 'm', tablet: 'l' }}
>
  {/* stacks on phones, sits side-by-side on tablets */}
</Box>

Testing and Maintaining the System

A design system is only as good as its reliability. Cover components with unit tests for logic and rendering, integration tests for how they compose, and visual regression checks to catch unintended UI changes. Document the library with Storybook so the whole team can browse every component and its variants, and version it deliberately so upgrades never silently break consuming screens.

Build Better Mobile Apps

For Developers: AI Mobile Launcher ships a complete design system built on Restyle, theme tokens, Box/Text primitives, a component library, dark and light mode, and responsive variants, all wired up out of the box.

For Founders: Need a mobile app with a polished, consistent design system from day one? AI Mobile Launcher gives you that foundation without the weeks of setup.