Fix: NativeWind Not Working — Styles Not Applying, Dark Mode Broken, or Metro Bundler Errors
Quick Answer
How to fix NativeWind issues — Tailwind CSS for React Native setup, Metro bundler configuration, className prop, dark mode, responsive styles, and Expo integration.
The Problem
Tailwind classes have no effect on React Native components:
import { View, Text } from 'react-native';
function App() {
return (
<View className="flex-1 items-center justify-center bg-blue-500">
<Text className="text-white text-2xl font-bold">Hello</Text>
</View>
);
}
// No styles applied — plain unstyled viewOr Metro bundler throws an error:
error: SyntaxError: Unexpected token (NativeWind CSS)Or dark mode classes don’t work:
<View className="bg-white dark:bg-gray-900">
// Always shows white — dark mode is ignoredWhy This Happens
NativeWind bridges Tailwind CSS and React Native. It compiles Tailwind utilities into React Native StyleSheet objects at build time:
- NativeWind v4 requires a Metro CSS transformer — the Metro bundler must be configured to process CSS. Without the transformer,
classNameprops are ignored because React Native doesn’t natively support CSS classes. - Tailwind must be configured with the right content paths —
tailwind.config.jsneeds to scan your React Native component files. If thecontentarray doesn’t include your source files, no utilities are generated. classNamemust be enabled on React Native components — in NativeWind v4, components fromreact-nativeautomatically supportclassName. But custom components or third-party libraries need wrapping withcssInteroporremapProps.- Dark mode requires
useColorScheme— React Native doesn’t have CSS media queries. NativeWind uses React Native’suseColorSchemehook. Thedark:variant only works when the system color scheme is dark or you manually set it.
Fix 1: Setup NativeWind v4 with Expo
npx expo install nativewind tailwindcss react-native-reanimated
npx expo install -- --save-dev prettier-plugin-tailwindcss// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./app/**/*.{js,jsx,ts,tsx}',
'./components/**/*.{js,jsx,ts,tsx}',
'./src/**/*.{js,jsx,ts,tsx}',
],
presets: [require('nativewind/preset')],
theme: {
extend: {
colors: {
primary: '#3b82f6',
secondary: '#64748b',
},
},
},
plugins: [],
};/* global.css */
@tailwind base;
@tailwind components;
@tailwind utilities;// metro.config.js
const { getDefaultConfig } = require('expo/metro-config');
const { withNativeWind } = require('nativewind/metro');
const config = getDefaultConfig(__dirname);
module.exports = withNativeWind(config, { input: './global.css' });// app/_layout.tsx (Expo Router) or App.tsx
import '../global.css'; // Import CSS at the entry point
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="index" />
</Stack>
);
}// nativewind-env.d.ts — TypeScript support
/// <reference types="nativewind/types" />Fix 2: Use Tailwind Classes
import { View, Text, Pressable, ScrollView, Image } from 'react-native';
function HomeScreen() {
return (
<ScrollView className="flex-1 bg-white dark:bg-gray-900">
{/* Layout */}
<View className="px-4 py-6">
<Text className="text-3xl font-bold text-gray-900 dark:text-white">
Dashboard
</Text>
<Text className="text-gray-500 dark:text-gray-400 mt-1">
Welcome back!
</Text>
</View>
{/* Card */}
<View className="mx-4 p-4 bg-white dark:bg-gray-800 rounded-2xl shadow-md border border-gray-100 dark:border-gray-700">
<View className="flex-row items-center gap-3">
<Image
source={{ uri: 'https://example.com/avatar.jpg' }}
className="w-12 h-12 rounded-full"
/>
<View className="flex-1">
<Text className="text-lg font-semibold text-gray-900 dark:text-white">
Alice Johnson
</Text>
<Text className="text-sm text-gray-500">[email protected]</Text>
</View>
</View>
</View>
{/* Button */}
<Pressable className="mx-4 mt-4 bg-primary py-3 rounded-xl active:opacity-80">
<Text className="text-white text-center font-semibold text-lg">
Continue
</Text>
</Pressable>
{/* Responsive — platform-specific */}
<View className="mt-4 px-4 ios:pb-8 android:pb-4">
<Text className="text-sm text-gray-400">
Platform-specific padding
</Text>
</View>
</ScrollView>
);
}Fix 3: Dark Mode
import { useColorScheme } from 'nativewind';
import { View, Text, Pressable } from 'react-native';
function SettingsScreen() {
const { colorScheme, setColorScheme, toggleColorScheme } = useColorScheme();
return (
<View className="flex-1 bg-white dark:bg-gray-900 p-4">
<Text className="text-xl font-bold text-gray-900 dark:text-white">
Appearance
</Text>
<View className="mt-4 gap-2">
<Pressable
onPress={() => setColorScheme('light')}
className={`p-4 rounded-xl border ${
colorScheme === 'light'
? 'border-primary bg-blue-50 dark:bg-blue-900/20'
: 'border-gray-200 dark:border-gray-700'
}`}
>
<Text className="font-medium text-gray-900 dark:text-white">Light</Text>
</Pressable>
<Pressable
onPress={() => setColorScheme('dark')}
className={`p-4 rounded-xl border ${
colorScheme === 'dark'
? 'border-primary bg-blue-50 dark:bg-blue-900/20'
: 'border-gray-200 dark:border-gray-700'
}`}
>
<Text className="font-medium text-gray-900 dark:text-white">Dark</Text>
</Pressable>
<Pressable
onPress={() => setColorScheme('system')}
className="p-4 rounded-xl border border-gray-200 dark:border-gray-700"
>
<Text className="font-medium text-gray-900 dark:text-white">System</Text>
</Pressable>
</View>
</View>
);
}Fix 4: Third-Party Component Styling
// Third-party components don't support className by default
// Use cssInterop to add className support
import { cssInterop } from 'nativewind';
import { SafeAreaView } from 'react-native-safe-area-context';
import Svg, { Path } from 'react-native-svg';
import { BlurView } from 'expo-blur';
// Remap className to the component's style prop
cssInterop(SafeAreaView, { className: 'style' });
cssInterop(BlurView, { className: 'style' });
cssInterop(Svg, { className: { target: 'style', nativeStyleToProp: { width: true, height: true } } });
// Now you can use className on these components
<SafeAreaView className="flex-1 bg-white">
<BlurView className="absolute inset-0" intensity={80} />
</SafeAreaView>Fix 5: Custom Components
// Reusable styled components
import { View, Text, Pressable, type PressableProps } from 'react-native';
import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';
// cn utility
export function cn(...inputs: (string | undefined | false)[]) {
return inputs.filter(Boolean).join(' ');
}
// Button with variants
const buttonVariants = cva(
'flex-row items-center justify-center rounded-xl',
{
variants: {
variant: {
default: 'bg-primary active:bg-blue-600',
secondary: 'bg-gray-100 dark:bg-gray-800 active:bg-gray-200',
destructive: 'bg-red-500 active:bg-red-600',
outline: 'border-2 border-gray-300 dark:border-gray-600 active:bg-gray-50',
ghost: 'active:bg-gray-100 dark:active:bg-gray-800',
},
size: {
sm: 'px-3 py-2',
md: 'px-4 py-3',
lg: 'px-6 py-4',
},
},
defaultVariants: {
variant: 'default',
size: 'md',
},
}
);
const buttonTextVariants = cva('font-semibold text-center', {
variants: {
variant: {
default: 'text-white',
secondary: 'text-gray-900 dark:text-white',
destructive: 'text-white',
outline: 'text-gray-900 dark:text-white',
ghost: 'text-gray-900 dark:text-white',
},
size: {
sm: 'text-sm',
md: 'text-base',
lg: 'text-lg',
},
},
defaultVariants: { variant: 'default', size: 'md' },
});
interface ButtonProps extends PressableProps, VariantProps<typeof buttonVariants> {
title: string;
className?: string;
}
export function Button({ title, variant, size, className, ...props }: ButtonProps) {
return (
<Pressable className={cn(buttonVariants({ variant, size }), className)} {...props}>
<Text className={buttonTextVariants({ variant, size })}>{title}</Text>
</Pressable>
);
}
// Usage
<Button title="Sign In" variant="default" size="lg" />
<Button title="Cancel" variant="outline" />
<Button title="Delete" variant="destructive" />Fix 6: Animations and Transitions
// NativeWind v4 supports transition utilities with Reanimated
import { View, Pressable, Text } from 'react-native';
function AnimatedCard() {
const [expanded, setExpanded] = useState(false);
return (
<Pressable onPress={() => setExpanded(!expanded)}>
<View
className={cn(
'bg-white dark:bg-gray-800 rounded-2xl p-4 transition-all duration-300',
expanded ? 'shadow-xl scale-[1.02]' : 'shadow-md',
)}
>
<Text className="font-bold text-lg text-gray-900 dark:text-white">
Tap to expand
</Text>
{expanded && (
<Text className="mt-2 text-gray-600 dark:text-gray-400">
Additional content shown when expanded.
</Text>
)}
</View>
</Pressable>
);
}Still Not Working?
Classes have no effect — the Metro config is missing withNativeWind. Add it to metro.config.js and restart Metro: npx expo start --clear. Also import global.css in your root layout.
“Unexpected token” in Metro bundler — Metro can’t process CSS without the NativeWind transformer. Ensure withNativeWind(config, { input: './global.css' }) wraps your Metro config. Clear the cache: npx expo start --clear.
Dark mode doesn’t work — dark: classes require the system to be in dark mode, or use setColorScheme('dark') from useColorScheme(). NativeWind respects the system setting by default. To override, wrap your app in a color scheme provider.
Third-party components ignore className — only React Native core components support className out of the box. Use cssInterop() to add support to third-party components like SafeAreaView, BlurView, etc.
For related mobile issues, see Fix: Expo Not Working and Fix: React Native Reanimated Not Working.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Tamagui Not Working — Styles Not Applying, Compiler Errors, or Web/Native Mismatch
How to fix Tamagui UI kit issues — setup with Expo, theme tokens, styled components, animations, responsive props, media queries, and cross-platform rendering.
Fix: Expo Router Not Working — Routes Not Matching, Layout Nesting Wrong, or Deep Links Failing
How to fix Expo Router issues — file-based routing, layout routes, dynamic segments, tabs and stack navigation, modal routes, authentication flows, and deep linking configuration.
Fix: React Native Paper Not Working — Theme Not Applying, Icons Missing, or Components Unstyled
How to fix React Native Paper issues — PaperProvider setup, Material Design 3 theming, custom color schemes, icon configuration, dark mode, and Expo integration.
Fix: React Navigation Not Working — Screens Not Rendering, TypeScript Errors, or Gestures Broken
How to fix React Navigation issues — stack and tab navigator setup, TypeScript typing, deep linking, screen options, nested navigators, authentication flow, and performance optimization.