Design system with CSS variables
NativeWind v4+ uses CSS variables (custom properties) to create flexible, customizable themes. This approach allows you to define design tokens once and reuse them throughout your application.
The @theme directive
Define your design tokens using the @theme directive in your CSS file:
@theme {
--elevation-xs: 1;
--elevation-sm: 3;
--elevation-md: 6;
--elevation-lg: 8;
--elevation-xl: 13;
--elevation-2xl: 24;
--elevation-none: 0;
}
These variables can then be referenced in your custom utilities:
@utility elevation-* {
-rn-elevation: --value(--elevation- * );
}
The @theme directive is processed at build time by the Tailwind CSS compiler, ensuring optimal performance.
Color customization
NativeWind supports the full Tailwind color palette, but you can customize it to match your brand.
Using default colors
All Tailwind color utilities work out of the box:
Text colors
Background colors
Border colors
< Text className = "text-blue-500" > Blue text </ Text >
< Text className = "text-red-600" > Red text </ Text >
< Text className = "text-green-400" > Green text </ Text >
< Text className = "text-gray-700" > Gray text </ Text >
< View className = "bg-purple-500" >
< Text > Purple background </ Text >
</ View >
< View className = "bg-yellow-200" >
< Text > Yellow background </ Text >
</ View >
< View className = "border-2 border-indigo-500" >
< Text > Indigo border </ Text >
</ View >
Custom color utilities
Create custom color utilities that reference your theme variables:
@utility color-* {
color: --value(--color- * );
}
@utility tint-* {
-rn-tint: --value(--color- * );
@prop -rn-tint tint;
}
Now you can use these utilities in your components:
< Text className = "color-primary" > Primary color text </ Text >
< Image source = { icon } className = "tint-accent" />
Define different design tokens for different platforms using media queries:
Font families
:root {
@ media ios {
--font-sans : System ;
--font-serif : Georgia ;
--font-mono : Menlo;
}
@media android {
--font-sans: SystemAndroid;
--font-serif: sans-serif ;
--font-mono: monospace;
}
}
Use these fonts in your components:
< Text className = "font-sans" > System font for each platform </ Text >
< Text className = "font-mono" > Monospace font for each platform </ Text >
Platform-specific CSS variables automatically apply the correct value based on where your app is running.
Spacing and sizing
Create a consistent spacing system:
@theme {
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
--spacing-2xl: 3rem;
}
Reference these in custom utilities:
@utility gap-* {
gap: --value(--spacing- * );
}
Creating a design system
Build a comprehensive design system by organizing your theme variables:
Define your color palette
Create semantic color names that describe their purpose: @theme {
/* Brand colors */
--color-primary: #3b82f6 ;
--color-secondary: #8b5cf6 ;
--color-accent: #f59e0b;
/* Semantic colors */
--color-success: #10b981 ;
--color-warning: #f59e0b;
--color-error: #ef4444;
--color-info: #3b82f6 ;
/* Neutral colors */
--color-background: #ffffff;
--color-surface: #f9fafb;
--color-border: #e5e7eb;
--color-text-primary: #111827 ;
--color-text-secondary: #6b7280 ;
}
Create typography tokens
Define font sizes, weights, and line heights: @theme {
/* Font sizes */
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 1.875rem;
/* Font weights */
--font-normal: 400;
--font-medium: 500;
--font-semibold: 600;
--font-bold: 700;
}
Add spacing and layout tokens
Establish consistent spacing throughout your app: @theme {
/* Spacing scale */
--space-0: 0;
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-6: 1.5rem;
--space-8: 2rem;
--space-12: 3rem;
/* Border radius */
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
--radius-xl: 1rem;
--radius-full: 9999px;
}
Define shadow and elevation
Create depth with consistent shadow styles: @theme {
/* Elevation for Android */
--elevation-xs: 1;
--elevation-sm: 3;
--elevation-md: 6;
--elevation-lg: 8;
--elevation-xl: 13;
--elevation-2xl: 24;
/* Shadow colors (for iOS/web) */
--shadow-color: rgba(0, 0, 0, 0 .1 );
--shadow-color-dark: rgba(0, 0, 0, 0 .3 );
}
Using theme variables in components
Once you’ve defined your design system, use it consistently across your components:
button-component.tsx
card-component.tsx
input-component.tsx
import { Pressable , Text } from 'react-native' ;
export function Button ({ children , variant = 'primary' }) {
const baseClasses = 'px-6 py-3 rounded-lg' ;
const variantClasses = {
primary: 'bg-blue-500 active:bg-blue-600' ,
secondary: 'bg-purple-500 active:bg-purple-600' ,
outline: 'border-2 border-blue-500 active:bg-blue-50' ,
};
return (
< Pressable className = { ` ${ baseClasses } ${ variantClasses [ variant ] } ` } >
< Text className = "text-white font-semibold text-center" >
{ children }
</ Text >
</ Pressable >
);
}
Dynamic theming with context
For runtime theme switching, use React Context with NativeWind’s VariableContextProvider:
import { createContext , useContext , useState } from 'react' ;
import { VariableContextProvider } from 'nativewind' ;
const ThemeContext = createContext ( null );
export function ThemeProvider ({ children }) {
const [ theme , setTheme ] = useState ( 'light' );
const themeVars = {
'--color-background' : theme === 'light' ? '#ffffff' : '#111827' ,
'--color-text' : theme === 'light' ? '#111827' : '#f9fafb' ,
};
return (
< ThemeContext.Provider value = { { theme , setTheme } } >
< VariableContextProvider variables = { themeVars } >
{ children }
</ VariableContextProvider >
</ ThemeContext.Provider >
);
}
export const useTheme = () => useContext ( ThemeContext );
Runtime theme switching with Context has performance implications. For most apps, use the built-in dark mode support instead.
Safe area support
NativeWind includes support for safe area utilities through the tailwindcss-safe-area plugin:
@import "tailwindcss-safe-area" ;
Use safe area utilities in your components:
< View className = "pt-safe" >
< Text > Content respects safe area </ Text >
</ View >
< View className = "pb-safe px-4" >
< Text > Bottom safe area padding </ Text >
</ View >
Best practices
Name your theme variables based on their purpose, not their appearance: /* Good: Semantic names */
--color-primary
--color-danger
--color-text-body
/* Avoid: Appearance-based names */
--color-blue
--color-red
--color-dark-gray
Keep platform differences minimal
Document your design system
Create a reference for your design tokens so your team understands when to use each one: // design-system.ts
export const designTokens = {
colors: {
primary: 'Primary brand color for CTAs and key actions' ,
secondary: 'Secondary brand color for accents' ,
// ...
},
spacing: {
sm: 'Use for tight spacing between related elements' ,
md: 'Default spacing for most UI elements' ,
// ...
},
};
Next steps
Dark mode Add dark mode support to your theme
CSS variables Deep dive into CSS variable customization
Tailwind config Extend Tailwind with custom configuration
Plugins Create custom Tailwind plugins