Skip to main content

Expo Integration

NativeWind works seamlessly with Expo, providing the fastest way to build cross-platform applications with Tailwind CSS styling. This guide covers setup for Expo SDK 54 and newer.
This guide assumes you’re using Expo SDK 54+ and NativeWind v5 (preview). For v4.1 setup, see the official NativeWind documentation.

Prerequisites

Before starting, ensure you have:
  • Node.js 20+ installed
  • Expo CLI installed globally or use npx
  • Basic familiarity with React Native and Expo

Installation

1

Create a New Expo Project (Optional)

If you don’t have an existing project, create one:
npx create-expo-app my-app
cd my-app
Or use the pre-configured starter:
# NativeWind v4.1 (stable)
npx rn-new@latest --nativewind

# NativeWind v5 (preview)
npx rn-new@next --nativewind
Using rn-new creates a project with NativeWind already configured. Skip to Usage if you use this method.
2

Install Dependencies

Install NativeWind and its peer dependencies:
npm install nativewind tailwindcss react-native-css
For Tailwind CSS v4:
npm install @tailwindcss/postcss
3

Install Additional Dependencies

NativeWind requires these Expo and React Native packages:
npx expo install expo-status-bar expo-system-ui react-native-reanimated react-native-worklets
These packages enable:
  • expo-status-bar: Status bar theming
  • expo-system-ui: System UI color management
  • react-native-reanimated: Smooth animations
  • react-native-worklets: Background thread execution

Configuration

1

Configure Metro Bundler

Create or update metro.config.js in your project root:
metro.config.js
const { getDefaultConfig } = require('expo/metro-config');
const { withNativewind } = require('nativewind/metro');

const config = getDefaultConfig(__dirname);

module.exports = withNativewind(config);
The withNativewind wrapper configures Metro to:
  • Process CSS files through the NativeWind compiler
  • Generate TypeScript definitions
  • Enable global className support
2

Configure Babel

Create or update babel.config.js:
babel.config.js
module.exports = function (api) {
  api.cache(true);
  
  return {
    presets: [['babel-preset-expo']],
  };
};
The babel-preset-expo preset includes necessary transformations for NativeWind. No additional Babel plugins are required.
3

Configure PostCSS

Create postcss.config.mjs in your project root:
postcss.config.mjs
export default {
  plugins: {
    '@tailwindcss/postcss': {},
  },
};
This configures Tailwind CSS v4’s PostCSS plugin to process your styles.
4

Create Global CSS File

Create global.css in your project root:
global.css
@import "tailwindcss/theme.css" layer(theme);
@import "tailwindcss/preflight.css" layer(base);
@import "tailwindcss/utilities.css";
@import "nativewind/theme";
This imports:
  • Tailwind’s theme configuration
  • Base styles (Preflight)
  • Utility classes
  • NativeWind-specific theme extensions
5

Import Global CSS

Import the CSS file in your app entry point (e.g., App.tsx or src/App.tsx):
App.tsx
import './global.css';
import { Text, View } from 'react-native';

export default function App() {
  return (
    <View className="flex-1 justify-center items-center bg-white">
      <Text className="text-2xl font-bold text-blue-500">
        Hello NativeWind!
      </Text>
    </View>
  );
}
6

Configure TypeScript (Optional)

NativeWind automatically generates type definitions. The nativewind-env.d.ts file is created automatically:
nativewind-env.d.ts
/// <reference types="react-native-css/types" />

// NOTE: This file should not be edited and should be committed 
// with your source code. It is generated by react-native-css.
Do not edit this file manually. It’s generated by NativeWind and should be committed to version control.
To disable automatic type generation:
metro.config.js
module.exports = withNativewind(config, {
  disableTypeScriptGeneration: true,
});

App Configuration

Update your app.config.ts or app.json to support dark mode:
import type { ConfigContext, ExpoConfig } from 'expo/config';

export default ({ config }: ConfigContext): ExpoConfig => {
  return {
    ...config,
    name: 'my-app',
    slug: 'my-app',
    userInterfaceStyle: 'automatic',
    ios: {
      bundleIdentifier: 'com.myapp',
    },
    android: {
      package: 'com.myapp',
    },
  };
};
The userInterfaceStyle: 'automatic' setting enables automatic dark mode support.

Usage

Start using Tailwind classes in your components:
import { View, Text, Pressable } from 'react-native';
import './global.css';

export default function App() {
  return (
    <View className="flex-1 items-center justify-center bg-gray-50 dark:bg-gray-900">
      <View className="p-6 bg-white dark:bg-gray-800 rounded-lg shadow-lg">
        <Text className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
          Welcome to NativeWind
        </Text>
        <Text className="text-base text-gray-600 dark:text-gray-300 mb-6">
          Tailwind CSS for React Native
        </Text>
        <Pressable className="bg-blue-500 hover:bg-blue-600 active:bg-blue-700 px-6 py-3 rounded-md">
          <Text className="text-white font-semibold text-center">
            Get Started
          </Text>
        </Pressable>
      </View>
    </View>
  );
}

Running Your App

Start the Expo development server:
npm start
# or
expo start
Use expo start --clear to clear the Metro bundler cache if you encounter styling issues after configuration changes.

Platform-Specific Features

iOS Specific

NativeWind automatically handles iOS-specific styling:
  • Safe Areas: Use the tailwindcss-safe-area plugin for notch/island support
  • Native Shadows: Box shadows are automatically converted to iOS shadow properties

Android Specific

For better shadow support on Android:
<View className="shadow-lg elevation-5 android:elevation-8">
  <Text>Card with shadow</Text>
</View>
Use elevation-* classes for Android-specific elevation.

Web Specific

When running on web, NativeWind uses CSS stylesheets for optimal performance:
<View className="web:cursor-pointer web:hover:shadow-xl">
  <Text>Web-optimized component</Text>
</View>

Troubleshooting

  1. Ensure global.css is imported in your app entry point
  2. Clear Metro bundler cache: expo start --clear
  3. Verify metro.config.js includes withNativewind wrapper
  4. Check that postcss.config.mjs is properly configured
  1. Verify nativewind-env.d.ts exists in your project root
  2. Restart your TypeScript server in VS Code
  3. Check tsconfig.json includes the types directory
  4. Ensure react-native-css types are installed
  1. Set userInterfaceStyle: 'automatic' in app.config.ts
  2. Use dark: prefix for dark mode classes
  3. Test on a physical device or simulator with dark mode enabled
  1. Ensure react-native-web is installed: npx expo install react-native-web
  2. Verify PostCSS configuration is correct
  3. Clear .expo and node_modules/.cache directories

Advanced Configuration

Customizing Metro Options

Pass custom options to withNativewind:
metro.config.js
module.exports = withNativewind(config, {
  // Disable TypeScript generation
  disableTypeScriptGeneration: false,
  
  // Custom TypeScript path
  typescriptEnvPath: 'nativewind-env.d.ts',
  
  // Enable global className polyfill
  globalClassNamePolyfill: true,
});

Expo Router Integration

For apps using Expo Router, import global CSS in your root layout:
app/_layout.tsx
import '../global.css';
import { Stack } from 'expo-router';

export default function Layout() {
  return <Stack />;
}

Next Steps

Core Concepts

Learn how styling works in NativeWind

Dark Mode

Implement dark mode in your app

Custom Styles

Add custom utilities and components

TypeScript

Configure TypeScript for NativeWind