Skip to main content
Mobile Launcher
Learning & TutorialsMobile Development

Styling

Theming with Restyle

Styling in React Native

We do NOT use StyleSheet.create or inline styles. We use Restyle by Shopify. It provides a type-safe theme system that scales.

The Theme

Located at src/ui/style/theme.ts. It defines your colors, spacing, and variants.

Typescript
// Accessing the theme in code
import { useTheme } from '@shopify/restyle';
const theme = useTheme<Theme>();
const primaryColor = theme.colors.primary;

How to Style Components

Instead of creating a style object, pass styles as props.

1. Margins & Padding (Spacing)

Use shorthand props from the theme spacing scale (xs, s, m, l, xl).

Tsx
<Box padding="m" marginTop="xl">
  <Text>Content</Text>
</Box>
PropCSS Equivalent
mmargin
ppadding
mxmarginHorizontal
pypaddingVertical

2. Colors

Reference colors directly by name.

Tsx
<Box backgroundColor="primary" borderColor="border" borderWidth={1}>
  <Text color="textPrimary">Hello</Text>
</Box>

3. Layout (Flexbox)

Tsx
<Box 
  flex={1} 
  flexDirection="row" 
  justifyContent="space-between" 
  alignItems="center"
>
  <Text>Left</Text>
  <Text>Right</Text>
</Box>

Variants

Variants allow you to define preset styles for components.

Tsx
// Text Variants (defined in theme.textVariants)
<Text variant="h1">Heading 1</Text>
<Text variant="body">Body Text</Text>
<Text variant="caption">Caption</Text>

// Card Variants
<Card variant="elevated">...</Card>
<Card variant="outlined">...</Card>

Defining Your Own Variants

Variants live in the theme, not in components. To add a new text style, extend textVariants in src/ui/style/theme.ts — every <Text variant="..."> in the app instantly gains the new option, fully typed:

Typescript
// src/ui/style/theme.ts
textVariants: {
  h1: { fontFamily: 'Inter-Bold', fontSize: 32, color: 'textPrimary' },
  body: { fontFamily: 'Inter-Regular', fontSize: 16, color: 'textPrimary' },
  caption: { fontFamily: 'Inter-Regular', fontSize: 12, color: 'textMuted' },
  // add your own:
  buttonLabel: { fontFamily: 'Inter-SemiBold', fontSize: 16, color: 'background' },
},

The same pattern applies to cardVariants, buttonVariants, and any other component variant key. Because the variant name is checked against the theme at compile time, a typo like variant="bodyy" is caught before you ever run the app.

Responsive Styles

Restyle props accept breakpoint objects, so one component adapts to phones and tablets without a second layout. The breakpoints are defined once in the theme:

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

Dark Mode

Restyle handles Dark Mode automatically. If you use backgroundColor="background", it will automatically switch between light (#FFFFFF) and dark (#000000) based on the active theme.

The boilerplate ships a light and a dark theme with the same shape. The active theme is chosen from the device color scheme via useColorScheme() and passed to Restyle's ThemeProvider, so toggling the system setting re-themes the whole app with no per-component work. This only works if every component reads semantic color names (background, textPrimary, border) rather than literal hex values — which is exactly why the rule below matters.

[!TIP] Never hardcode hex codes like #FF0000. Always add them to src/ui/style/tokens/colors.ts and reference them via the theme.

Why Not StyleSheet?

StyleSheet.create works, but it has no concept of your theme: nothing stops a teammate from typing #3B82F6 in twelve different files, and a rebrand becomes a find-and-replace. Restyle centralizes every token, makes dark mode free, and turns design-system drift into a compile error. The small upfront learning curve pays for itself the first time you change a brand color in one place and watch the whole app update.