Overview
NativeWind fully supports CSS variables (custom properties), allowing you to create dynamic, theme-aware applications. Unlike traditional React Native styling, CSS variables can be changed at runtime, enabling features like dark mode, user themes, and dynamic theming.
Basic Usage
Defining Variables
Define CSS variables in your theme file using the @theme block:
@theme {
--color-primary: #3b82f6 ;
--color-secondary: #8b5cf6 ;
--color-background: #ffffff;
--color-text: #000000 ;
--spacing-unit: 8px;
--border-radius: 8px;
}
Using Variables in Utilities
Reference variables in custom utilities:
@utility bg-primary {
background-color : var(--color-primary);
}
@utility text-primary {
color: var(--color-primary);
}
Use them in your components:
import { View , Text } from "react-native" ;
export default function Card () {
return (
< View className = "bg-primary p-4 rounded" >
< Text className = "text-white" > Primary Card </ Text >
</ View >
);
}
Runtime Variables
NativeWind exposes APIs for working with CSS variables at runtime, enabling dynamic theming.
useUnstableNativeVariable
Access and modify CSS variables from your components:
import { View , Text , Button } from "react-native" ;
import { useUnstableNativeVariable } from "nativewind" ;
export default function ThemeDemo () {
const [ primaryColor , setPrimaryColor ] = useUnstableNativeVariable ( "--color-primary" );
const changeTheme = () => {
setPrimaryColor ( "#ef4444" ); // Change to red
};
return (
< View className = "flex-1 p-4" >
< View className = "bg-primary p-6 rounded-lg" >
< Text className = "text-white text-lg" > Current Theme </ Text >
< Text className = "text-white/70" > Primary: { primaryColor } </ Text >
</ View >
< Button title = "Change Theme" onPress = { changeTheme } />
</ View >
);
}
The useUnstableNativeVariable hook is marked as unstable and its API may change in future versions. Use with caution in production applications.
VariableContextProvider
Provide CSS variables to a subtree of your application:
import { View , Text } from "react-native" ;
import { VariableContextProvider } from "nativewind" ;
export default function App () {
return (
< VariableContextProvider
value = { {
"--color-primary" : "#3b82f6" ,
"--color-secondary" : "#8b5cf6" ,
} }
>
< View className = "bg-primary p-4" >
< Text className = "text-secondary" > Themed content </ Text >
</ View >
</ VariableContextProvider >
);
}
Nested Contexts
You can nest VariableContextProvider components to create scoped themes:
import { View , Text } from "react-native" ;
import { VariableContextProvider } from "nativewind" ;
export default function NestedThemes () {
return (
< VariableContextProvider value = { { "--color-primary" : "#3b82f6" } } >
< View className = "bg-primary p-4" >
< Text className = "text-white" > Blue Theme </ Text >
< VariableContextProvider value = { { "--color-primary" : "#ef4444" } } >
< View className = "bg-primary p-4 mt-4" >
< Text className = "text-white" > Red Theme (nested) </ Text >
</ View >
</ VariableContextProvider >
</ View >
</ VariableContextProvider >
);
}
Dark Mode with CSS Variables
Implement dark mode using CSS variables and the dark: variant:
@theme {
/* Light mode colors */
--color-background: #ffffff;
--color-text: #000000 ;
--color-card: #f3f4f6;
--color-border: #e5e7eb;
/* Dark mode colors */
@media (prefers-color-scheme: dark) {
--color-background: #000000 ;
--color-text: #ffffff;
--color-card: #1f2937 ;
--color-border: #374151 ;
}
}
NativeWind automatically detects your device’s color scheme using React Native’s useColorScheme() hook and applies the appropriate CSS variables.
Semantic Color System
Create a semantic color system using CSS variables:
@theme {
/* Base palette */
--color-blue-500: #3b82f6 ;
--color-red-500: #ef4444;
--color-green-500: #10b981 ;
--color-gray-100: #f3f4f6;
--color-gray-900: #111827 ;
/* Semantic colors - light mode */
--color-primary: var(--color-blue-500);
--color-error: var(--color-red-500);
--color-success: var(--color-green-500);
--color-background: white;
--color-surface: var(--color-gray-100);
--color-text: var(--color-gray-900);
/* Semantic colors - dark mode */
@media (prefers-color-scheme: dark) {
--color-background: black;
--color-surface: var(--color-gray-900);
--color-text: var(--color-gray-100);
}
}
Usage:
< View className = "bg-[var(--color-surface)]" >
< Text className = "text-[var(--color-text)]" > Semantic theming </ Text >
< Text className = "text-[var(--color-primary)]" > Primary action </ Text >
< Text className = "text-[var(--color-error)]" > Error message </ Text >
</ View >
Define different variable values for each platform:
:root {
/* Default values */
--shadow-color : rgba ( 0 , 0 , 0 , 0.1 );
--shadow-elevation : 3 ;
@ media ios {
--shadow-color : rgba ( 0 , 0 , 0 , 0.15 );
--shadow-radius : 4 px ;
--shadow-offset-y : 2 px ;
}
@media android {
--shadow-elevation: 4;
}
}
Variable Namespaces
Organize variables using prefixes:
@theme {
/* Color variables */
--color-primary: #3b82f6 ;
--color-secondary: #8b5cf6 ;
/* Spacing variables */
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
--spacing-xl: 32px;
/* Typography variables */
--font-size-xs: 12px;
--font-size-sm: 14px;
--font-size-base: 16px;
--font-size-lg: 18px;
--font-size-xl: 24px;
/* Animation variables */
--duration-fast: 150ms;
--duration-base: 300ms;
--duration-slow: 500ms;
/* Elevation variables */
--elevation-sm: 2;
--elevation-md: 4;
--elevation-lg: 8;
--elevation-xl: 16;
}
Computed Variables
Create variables that reference other variables:
@theme {
/* Base values */
--spacing-unit: 8px;
--color-primary: #3b82f6 ;
/* Computed values */
--spacing-2x: calc(var(--spacing-unit) * 2);
--spacing-3x: calc(var(--spacing-unit) * 3);
--spacing-half: calc(var(--spacing-unit) / 2);
/* Color variations */
--color-primary-light: color-mix(in srgb, var(--color-primary) 70%, white);
--color-primary-dark: color-mix(in srgb, var(--color-primary) 70%, black);
}
color-mix() may have limited support in React Native. Test thoroughly on your target platforms.
Dynamic Theme Switching
Implement a complete theme switching system:
import React , { createContext , useContext , useState } from "react" ;
import { VariableContextProvider } from "nativewind" ;
const themes = {
light: {
"--color-background" : "#ffffff" ,
"--color-text" : "#000000" ,
"--color-primary" : "#3b82f6" ,
},
dark: {
"--color-background" : "#000000" ,
"--color-text" : "#ffffff" ,
"--color-primary" : "#60a5fa" ,
},
ocean: {
"--color-background" : "#0c4a6e" ,
"--color-text" : "#e0f2fe" ,
"--color-primary" : "#06b6d4" ,
},
};
type ThemeName = keyof typeof themes ;
const ThemeContext = createContext <{
theme : ThemeName ;
setTheme : ( theme : ThemeName ) => void ;
}>({
theme: "light" ,
setTheme : () => {},
});
export function ThemeProvider ({ children } : { children : React . ReactNode }) {
const [ theme , setTheme ] = useState < ThemeName >( "light" );
return (
< ThemeContext.Provider value = { { theme , setTheme } } >
< VariableContextProvider value = { themes [ theme ] } >
{ children }
</ VariableContextProvider >
</ ThemeContext.Provider >
);
}
export const useTheme = () => useContext ( ThemeContext );
CSS variables are resolved at runtime, but NativeWind optimizes this process during the build step. Variables defined in @theme are processed at build time when possible.
Changing CSS variables through useUnstableNativeVariable or VariableContextProvider only re-renders components that consume those specific variables, not the entire tree.
Static variable values are resolved at build time for maximum performance. Only dynamic runtime changes incur a performance cost.
Best Practices
Semantic Naming Use semantic names like --color-primary instead of --color-blue to make theming easier
Namespace Variables Group related variables with prefixes like --color-*, --spacing-*, --font-*
Document Your System Maintain a reference of all available variables and their purposes
Test Across Platforms Always test variable-based styling on iOS, Android, and web platforms
Debugging
Inspect current variable values at runtime:
import { useUnstableNativeVariable } from "nativewind" ;
function DebugVariables () {
const [ primary ] = useUnstableNativeVariable ( "--color-primary" );
const [ background ] = useUnstableNativeVariable ( "--color-background" );
console . log ( "Variables:" , { primary , background });
return (
< View >
< Text > Primary: { primary } </ Text >
< Text > Background: { background } </ Text >
</ View >
);
}
Advanced: Variables in Custom Utilities
Combine CSS variables with custom utilities:
@theme {
--elevation-card: 4;
--radius-card: 12px;
--color-card-bg: #ffffff;
}
@utility card {
background-color : var(--color-card-bg);
border-radius : var(--radius-card);
-rn-elevation: var(--elevation-card);
padding: 16px;
}
Usage:
< View className = "card" >
< Text > This card uses variable-based styling </ Text >
</ View >