×

Please try us on a desktop

Our app relies on some desktop browser features to render design files and interactable code. Unfortunately, we haven't been able to make these work on mobile yet.

Please try Kombai using a chromium based browser on desktop.

Tailwind

How to use Tailwind CSS with React Native

Published on: February 25, 2025

Styling a React Native application can often feel more complex compared to styling a web-based React project. Unlike the web, where CSS is the standard, React Native requires styles to be defined using JavaScript objects or external libraries. NativeWind bridges this gap by bringing Tailwind CSS syntax to React Native, making styling more intuitive, modular, and maintainable.

In this guide, we'll explore how to set up NativeWind, integrate Tailwind-style utilities into a React Native project, and build an interactive ecommerce product card.

What is NativeWind?

NativeWind is a utility-first styling library that enables you to use Tailwind CSS classes for styling React Native applications. It simplifies the styling process by bringing the utility classes of Tailwind to React Native components.

Unlike traditional React Native styling, where styles are defined using JavaScript objects inside the StyleSheet API, NativeWind provides a declarative, class-based approach similar to styling web applications.

One of the main advantages of using NativeWind is the elimination of the need for maintaining large, complex style objects. Instead, styles can be applied directly as class names, similar to how Tailwind CSS works on the web. This simplifies the styling process and makes it easier to read and understand the codebase.

How NativeWind works?

NativeWind functions as a utility-based styling system that transforms Tailwind CSS classes into optimized React Native styles. When you apply a Tailwind class to a component, NativeWind dynamically converts it into a corresponding React Native style object.

Under the hood, NativeWind processes styles during the build step and applies reactive styles at runtime with minimal overhead, handling changes like device orientation and dark mode efficiently.

Another key feature of NativeWind is its support for theming and customization. You can extend Tailwind's default settings with custom colors, font sizes, and utilities to match your design needs. This flexibility helps you create consistent UI for mobile apps.

Prerequisites

Before proceeding ahead, make sure you have the following:

  1. Knowledge of React Native and Tailwind
  2. Expo Go mobile app installed
  3. Node.js x version installed

Create Expo app

Step 1: To create a new Expo app- Go to the concerned directory, open the terminal and run the following command:

npx create-expo-app@latest your-app-name

Note: Replace your-app-name in the above command with the name of your app.

Step 2: Then, run the following commands to navigate to the project and reset the default example.

cd your-app-name
npm run reset-project

Step 3: Now, you will be asked the following question, type n to delete the default example.

Do you want to move existing files to /app-example instead of deleting them? (Y/n):

Note: The npm run reset-project is not mandatory but recommended as it will delete the default example and give you a clean starter to work with.

Step 4: Now, run the following command to start the development server.

npx expo start

Step 5: After executing the command, a QR code will appear on your terminal. Scan this QR code with the Expo Go app. If you're working with an Android or an iOS Simulator, you can start the app by pressing a or i.

Step 6: Edit app/index.tsx to edit the main screen.

Install NativeWind

Step 1: Install NativeWind & dependencies

Run the following command to install nativewind and its peer dependencies- tailwindcss, react-native-reanimated, etc.

npm install nativewind tailwindcss react-native-reanimated@3.16.2 react-native-safe-area-context

Step 2: Add Tailwind CSS

Run npx tailwind init to create the config file. Next, update the tailwind.config.js file by adding the paths of all your component files.

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./app/**/*.{js,jsx,ts,tsx}"],
  presets: [require("nativewind/preset")],
  theme: {
    extend: {},
  },
  plugins: [],
}

Step 3: Create CSS file

Create a global.css file at the root of your poject and add the following directives:

@tailwind base;
@tailwind components;
@tailwind utilities;

Step 4: Configure Babel

Create a babel.config.js file at the root and add the following code to it:

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

Step 5: Configure Metro

Create a metro.config.js file at the root and add the following code to it:

const { getDefaultConfig } = require("expo/metro-config");
const { withNativeWind } = require('nativewind/metro');

const config = getDefaultConfig(__dirname)

module.exports = withNativeWind(config, { input: './global.css' })

Step 5: Import CSS

In the app/_layout.tsx file, import the CSS file you created earlier:

import { Stack } from "expo-router";
import "../global.css" 

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

Step 6: Update app.json

Set the expo.web.bundler to metro(if not already set).

{
  "expo": {
    "web": {
      "bundler": "metro"
    }
  }
}

Step 7: Use Tailwind classes

Now, you can use the Tailwind utilties in your components:

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

export default function Index() {
  return (
    <View className="flex items-center justify-center bg-blue-500">
      <Text className="text-white text-lg">Hello, NativeWind!</Text>
    </View>
  );
}

Note: Restart the dev server if utilities are not working for the first time.

Build an Ecommerce Card with React Native and NativeWind

In this section, we'll explore how to create a product card in React Native and style it using NativeWind. We'll focus on building a state-aware component that responds to different user interactions. You can find the full code for the product card in this GitHub repository.

Component Architecture

When building complex UI structures in React Native, it's essential to break down components into smaller, reusable parts. This modular approach improves maintainability and ensures a clear separation of concerns. In our product card implementation, we use a hierarchical component structure where the main App component manages state, while individual components handle specific UI elements like displaying images, product details, and interactive buttons.

This architecture follows a parent-child relationship, where data flows downward through props, and user interactions are handled via callback functions passed back up to the parent. We centralize state management in the App component, preventing unnecessary prop drilling and ensuring that there is a single source of truth for the application’s state.

App
│
├── ProductImage
│   ├── NavigationButton (left)
│   ├── NavigationButton (right)
│   └── WishlistButton
│
├── ProductDetails
│   ├── RatingStars
│   └── CartButton
│
└── utils (Helper functions)
    ├── formatPrice
    ├── generateStars
    └── formatReviews

State Management

State management in this project revolves around three key data points:

  1. The currently displayed product
  2. The set of products added to the cart
  3. The set of wishlisted items

We use React’s useState hook to track these values efficiently. Instead of arrays, we utilize Set data structures to store cart and wishlist items. This approach allows for fast lookups, automatic duplicate prevention, and easy addition/removal of items.

const [currentProductIndex, setCurrentProductIndex] = useState(0);
const [cartItems, setCartItems] = useState(new Set());
const [wishlistItems, setWishlistItems] = useState(new Set());

Since Set objects provide efficient add and delete operations, they eliminate the need for complex filtering when updating the cart or wishlist. This makes state management more optimized, especially when dealing with larger product catalogs.

Styling Strategy

1. Base Container

For the main container, we use fixed dimensions to maintain a consistent layout. The background, rounded corners, and shadow effects are applied using their respective utility classes.

In React Native, images must be wrapped in an Image component, and absolute positioning is handled using relative and absolute styles.

Here, relative ensures that child elements (like wishlist and navigation buttons) are positioned correctly.

<View className="w-[365px] h-[400px] bg-white rounded-xl shadow-lg overflow-hidden">
  <View className="relative h-48 bg-gray-100">
    <Image source={{ uri: image }} className="w-full h-full object-cover" />
  </View>
</View>

2. Interactive Elements

Unlike <button> element, React Native provides TouchableOpacity for interactive elements like buttons. For our navigation and cart buttons, we implement state-based styling and positioning using absolute, top, and left/right.

// Navigation buttons
<TouchableOpacity className="absolute left-2 top-1/2 -translate-y-1/2 p-2 rounded-full bg-white/80" onPress={onPrevious}>
  <Text className="text-lg"></Text>
</TouchableOpacity>

// Cart button with dynamic styles
<TouchableOpacity 
  className={`
    w-full py-2 rounded-lg transition-all duration-200
    ${!availability 
      ? 'bg-gray-200 text-gray-500'
      : isInCart
      ? 'bg-gray-50 text-gray-700 border border-gray-200'
      : 'bg-blue-600 text-white'
    }
  `}
  onPress={() => toggleCart(product.id)}
>
  <Text className="text-center">
    {!availability ? "Out of Stock" : isInCart ? "✓ Added to Cart" : "Add to Cart"}
  </Text>
</TouchableOpacity>

3. Typography & Layout

To establish a clear visual hierarchy, this project applies a structured typography system that differentiates between primary and secondary content. By carefully adjusting text size, weight, and color, we ensure important details stand out while maintaining a visually balanced layout. Additionally, consistent spacing helps create a natural reading flow.

The combination of flex-based layout and typography styling enhances readability by ensuring that key details like the product name and price remain prominent. React Native relies on Text components for rendering text, so all textual elements must be wrapped accordingly.

<View className="flex-row justify-between items-start mb-2">
  <Text className="text-lg font-semibold text-gray-800">{name}</Text>
  <Text className="text-lg font-bold text-gray-800">{formatPrice(price)}</Text>
</View>

Bring Everything Together

Now, let's look at how the final App.js integrates all components to form a functional product card. The key takeaway here is the structured componentization—instead of placing everything in a single file, we split the UI into modular components that handle distinct responsibilities.

return (
  <View className="flex-1 items-center justify-center bg-gray-100">
    <View className="w-[365px] h-[400px] bg-white rounded-xl shadow-lg overflow-hidden">
      <ProductImage
        image={currentProduct.image}
        name={currentProduct.name}
        onPrevious={previousProduct}
        onNext={nextProduct}
        isWishlisted={isCurrentProductWishlisted}
        onWishlistToggle={toggleWishlist}
      />
      <ProductDetails
        product={currentProduct}
        isInCart={isCurrentProductInCart}
        onCartToggle={() => toggleCart(currentProduct.id)}
      />
    </View>
  </View>
);

To keep the application flexible and scalable, product details are also stored in an array. Each product object contains all the necessary fields for rendering the UI.

const products = [
  {
    id: 1,
    name: "Minimalist Watch",
    collection: "Classic Collection",
    price: 199.99,
    shipping: "Free Shipping",
    rating: 4.2,
    reviews: 4200,
    image: "...",
    color: "Silver",
    brand: "Timeless",
    availability: true
  },
  // More products...
];

Customize NativeWind theme

NativeWind allows for full customization of the default Tailwind theme. You can modify the tailwind.config.js file to define custom colors, fonts, spacing, and more.

To extend the default theme, update your configuration file as follows:

module.exports = {
  theme: {
    extend: {
      colors: {
        primary: '#1DA1F2',
        secondary: '#14171A',
      },
      fontSize: {
        xl: '1.5rem',
      },
    },
  },
  plugins: [],
};

Now, use can use these utilities in the components:

import { View, Text, TouchableOpacity } from 'react-native';

export default function CustomButton() {
  return (
    <TouchableOpacity className="bg-primary px-6 py-3 rounded-lg shadow-md">
      <Text className="text-secondary text-xl font-bold">Click Me</Text>
    </TouchableOpacity>
  );
}

What’s new in NativeWind v4.1?

The latest version(as of ) of NativeWind, v4.1, brings several improvements, including:

  1. Persistent Fast Refresh: Styles are now stored on disk when virtual modules are unavailable, ensuring fast refresh in both development and production environments.
  2. Faster Refresh Rate: Reduced costly Metro transforms for faster refresh times while maintaining functionality.
  3. Better Animation Support[Experimental]: Improves transitions and animations for a smoother UI experience.
  4. tvOS Support: Allows NativeWind to be used in react-native-tvos projects.
  5. Media Queries: Added support for dpi, dpcm, and dppx media queries.
  6. TypeScript Enhancements: Automatically configures TypeScript types for a better development experience.
  7. Expanded Dot Notation Support: Refined cssInterop targeting for improved flexibility.
  8. Better calc() Function Support: Allows parenthesis usage in calc() expressions, improving dynamic style calculations.
  9. Enhanced Development Tools: Introduces improved debugging and logging tools, making it easier to diagnose and resolve styling issues.

For detailed explanation of each update, visit official NativeWind blog.

Conclusion

Using NativeWind in React Native allows developers to write styles in a familiar utility-first approach without managing multiple StyleSheet objects.

With NativeWind, you can create visually appealing, responsive, and scalable mobile UIs with minimal effort. Whether you're working on an Ecommerce app, dashboard, or social platform, this approach will keep your styling concise, flexible, and maintainable.

Now that you’ve learned the fundamentals, you can extend this project further by adding API integrations, implementing animations, or customizing NativeWind’s theme to fit your design needs.