KhueApps
Home/React Native/Set up NativeWind in React Native Expo with TypeScript

Set up NativeWind in React Native Expo with TypeScript

Last updated: October 07, 2025

Overview

NativeWind brings Tailwind-like utility classes to React Native. In Expo (managed workflow), setup is straightforward: install NativeWind and Tailwind CSS, add the NativeWind Babel plugin, configure Tailwind, and optionally add TypeScript types.

This guide targets Expo (managed) projects and NativeWind v2.x.

Quickstart

  • Works with: Expo Go, development builds, Android, iOS, and web (via react-native-web).
  • You do not run the Tailwind CLI in NativeWind. The Babel plugin compiles className utilities to React Native style objects.

Prerequisites

  • Node 18+
  • Expo SDK 49+ (recommended 50 or newer)
  • TypeScript template (optional but used here)

1) Create or open an Expo app

# New app (TypeScript)
npx create-expo-app@latest my-app --template
cd my-app

If you already have an app, just continue in your project folder.

2) Install dependencies

# Using npm
npm install nativewind tailwindcss

# or with yarn
# yarn add nativewind tailwindcss

# or with pnpm
# pnpm add nativewind tailwindcss

3) Initialize Tailwind config

npx tailwindcss init

This creates tailwind.config.js.

4) Configure Tailwind

Edit tailwind.config.js:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./App.{js,jsx,ts,tsx}",
    "./app/**/*.{js,jsx,ts,tsx}",
    "./src/**/*.{js,jsx,ts,tsx}",
  ],
  theme: {
    extend: {
      colors: {
        brand: {
          500: "#5B8DEF",
          600: "#3F6FD6",
        },
      },
    },
  },
  plugins: [],
};

Notes:

  • content globs help editors and tools; NativeWind’s Babel plugin does the actual class compilation.
  • theme.extend lets you add custom tokens you can reference in classes (e.g., bg-brand-600).

5) Add the NativeWind Babel plugin

Edit babel.config.js:

module.exports = function (api) {
  api.cache(true);
  return {
    presets: ["babel-preset-expo"],
    plugins: ["nativewind/babel"],
  };
};

Restart the dev server after changing Babel config:

npx expo start -c

6) Add TypeScript types (TS only)

Edit tsconfig.json to include NativeWind’s types so className is recognized on React Native components:

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "types": ["nativewind/types"]
  }
}

Minimal working example (App.tsx)

import { StatusBar } from "expo-status-bar";
import { useState } from "react";
import { Text, View, Pressable } from "react-native";

export default function App() {
  const [on, setOn] = useState(false);

  return (
    <View className="flex-1 items-center justify-center bg-white dark:bg-black">
      <Text className="text-2xl font-semibold text-gray-900 dark:text-gray-100">
        NativeWind + Expo
      </Text>

      <Text className="mt-2 text-gray-600 dark:text-gray-300">
        Toggle below to switch styles
      </Text>

      <Pressable
        onPress={() => setOn((v) => !v)}
        className={
          on
            ? "mt-6 rounded-lg bg-brand-600 px-4 py-2"
            : "mt-6 rounded-lg bg-gray-800 px-4 py-2"
        }
      >
        <Text className="text-white font-medium">
          {on ? "On" : "Off"}
        </Text>
      </Pressable>

      <StatusBar style="auto" />
    </View>
  );
}

Run it:

npx expo start

Scan the QR with Expo Go or launch iOS/Android simulators.

Using with Expo Router (optional)

If you use expo-router, keep your content globs in tailwind.config.js pointing to the app directory (already included above). Example app/(tabs)/index.tsx:

import { View, Text } from "react-native";

export default function Home() {
  return (
    <View className="flex-1 items-center justify-center bg-white">
      <Text className="text-xl font-bold">Home</Text>
    </View>
  );
}

Styling non-primitive components

Third-party components won’t automatically accept className. Wrap them with NativeWind’s styled helper:

import { styled } from "nativewind";
import { Pressable } from "react-native";

const SPressable = styled(Pressable);

export function Button(props: React.ComponentProps<typeof SPressable>) {
  return (
    <SPressable className="rounded-md bg-brand-600 px-3 py-2" {...props} />
  );
}

Common pitfalls

  • Missing Babel plugin: If className appears to do nothing, ensure babel.config.js includes "nativewind/babel" and restart with cache clear.
  • TypeScript errors on className: Add "types": ["nativewind/types"] to tsconfig.json.
  • Dynamic class generation: Avoid building class names with string concatenation like "bg-" + color. The compiler can’t see those. Prefer conditional selections of known classes.
  • Unsupported CSS utilities: React Native doesn’t support all CSS features. Utilities that map to unsupported properties (e.g., backdrop-blur, some filters) won’t work.
  • Shadows on Android: Use elevation for Android shadows. Tailwind’s shadow utilities map to iOS shadows; Android requires elevation.
  • Dark mode: Use dark: variants with React Native Appearance or a theme provider. Ensure your app toggles color scheme or uses system preference.
  • Web-only assumptions: Some Tailwind plugins or pseudo-classes are web-only and won’t apply to native.

Performance notes

  • Keep class lists static where possible: Static className strings are compiled at build time to optimized style arrays.
  • Use simple conditionals: When variants are needed, select among a few static strings rather than concatenating fragments.
  • Prefer fewer, meaningful utilities: Many overlapping utilities create larger style arrays. Consolidate where reasonable.
  • Memoization: For frequently re-rendered lists, memoize rows and avoid recomputing variant choices.
  • Hermes and production: Production builds with Hermes and the Babel transform yield the best runtime performance versus JS-based style assembly.

Debugging tips

  • Force a clean restart after Babel or config changes: npx expo start -c.
  • Verify code reachability: The compiler only transforms classes present in your source files.
  • Print styles: Temporarily pass both className and an equivalent inline style to compare visual output when diagnosing issues.

FAQ

  • Do I need to run the Tailwind CLI or generate CSS?
    • No. NativeWind’s Babel plugin handles class transformation for React Native.
  • Does this work in Expo Go?
    • Yes. As long as the Babel plugin is configured, Expo Go will render NativeWind styles.
  • How do I add custom colors or fonts?
    • Extend theme in tailwind.config.js, then reference utilities like bg-brand-600 or font-[YourFontName] if the font is loaded in Expo.
  • Can I use NativeWind on web via Expo?
    • Yes. It works through react-native-web. Some utilities still reflect React Native’s style system rather than full CSS.
  • What about class collisions or ordering?
    • Later utilities in the class string win, similar to Tailwind on web. Order your utilities accordingly.

Next steps

  • Add app-wide theming (light/dark) and extract reusable styled components.
  • Define a small set of variant patterns for buttons, inputs, and headers to keep class names consistent across the app.

Series: React Native Intermediate tutorials

React Native