Ă—

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

Published on: February 25, 2025

Tailwind CSS has become a popular choice for styling modern web applications. When combined with React, it simplifies component styling, making it easier to maintain and scale projects while keeping the UI flexible and performant.

In this guide, we will cover the installation and setup of Tailwind CSS in React and build an e-commerce product card. Additionally, we will see how Tailwind works with Next.js and React Native, along with component libraries like Flowbite React and Material Tailwind.

Prerequisites

Before proceeding ahead, make sure you have the following:

  1. Knowledge of React and Tailwind.
  2. An IDE like VS Code, Cursor, etc.
  3. Node.js v18+ and npm installed.

Create React app

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

npm init vite@latest your-app-name --template react

Step 2: Once the React app is created, run the commands below to navigate to the folder and install dependencies.

cd your-app-name
npm install

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

Install Tailwind CSS

Now that your React app is created, follow the steps below to properly install and configure Tailwind CSS.

Step 1: Install Tailwind & dependencies

Run the following command to install Tailwind package along with its official Vite plugin.

npm install tailwindcss @tailwindcss/vite

Step 2: Add Vite plugin

Next, enable the Tailwind Vite plugin inside your Vite configuration file to ensure that styles are processed efficiently. Open vite.config.js (or vite.config.ts if using TypeScript) and modify it as follows:

import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
  plugins: [
    tailwindcss(),
  ],
})

Step 3: Import Tailwind

Now import Tailwind into your CSS file so that the utility classes are available globally.

@import "tailwindcss";

Step 4: Run build process

Start your dev server with npm run dev or the command configured in package.json file.

npm run dev

Step 5: Use Tailwind classes

Once Tailwind CSS is successfully installed and configured, you can start applying its utility classes directly to the React components.

export default function App() {
  return (
    <h1 className="text-2xl font-bold">
      Welcome to React!
    </h1>
  )
}

Build an e-commerce product card

In this section, we'll learn how to build a product card in React and style it with Tailwind, focusing on creating a state-aware component that adapts to various user interactions. The complete code of the product card can be found in the below CodeSandbox.

Component architecture

When building complex UI components, start by breaking down the structure into manageable, reusable pieces. In this product card, we've established a hierarchical component structure that separates concerns while maintaining clear communication channels between components. The main App component acts as the container and state manager, while specialized components handle specific UI elements like product images and details.

The component architecture follows a parent-child relationship where data flows downward through props, and interactions bubble up through callback functions. You'll notice that we've kept the state management centralized in the parent App component, which helps prevent prop drilling and maintains a single source of truth for our application state.

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

State management

The state management strategy in this project focuses on maintaining three key pieces of information. We use useState hook to manage the current product index and two Sets for cart and wishlist items. This approach provides an efficient way to track user interactions while maintaining performant operations.

When implementing the state management system, using Set data structures provides significant advantages for tracking selected items. The Set's built-in methods for adding and removing items eliminate the need for complex array operations, and the automatic handling of duplicates simplifies your logic considerably. This becomes particularly valuable when dealing with larger product catalogs or when implementing features like bulk selections.

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

Styling strategy

1. Base container

For the base container, we started with a fixed-dimension container for consistency across different viewport sizes while maintaining a clean, modern appearance through rounded corners and subtle shadows.

When you're implementing the container, you'll notice that the combination of fixed dimensions and overflow handling creates a reliable foundation for your card's content. The relative positioning on the image container sets up a positioning context for overlay elements, which becomes crucial when adding interactive elements like navigation buttons or wishlist toggles.

<div className="w-[365px] h-[400px] bg-white rounded-xl shadow-lg overflow-hidden">
  <div className="relative h-48 bg-gray-100">
    <img className="w-full h-full object-cover" />
  </div>
</div>

2. Interactive Elements

The navigation and cart buttons exemplify how to combine positioning, state-based styling, and hover effects to create user interactions.

We have used template literals for conditional styling. It provides a clean way to handle different states while maintaining readability. The transition utilities ensure smooth state changes, enhancing the overall user experience without requiring custom CSS animations.

// Navigation buttons with hover states
<button className="absolute left-2 top-1/2 -translate-y-1/2 p-1 rounded-full bg-white/80">

// Cart button with state-based styling
<button 
  className={`
    w-full py-2 rounded-lg transition-all duration-200
    ${!availability 
      ? 'bg-gray-200 text-gray-500 cursor-not-allowed'
      : isInCart
      ? 'bg-gray-50 text-gray-700 hover:bg-gray-100'
      : 'bg-blue-600 hover:bg-blue-700 text-white'
    }
  `}
>

3. Typography & Layout

Our project uses a carefully crafted type scale to distinguish between primary and secondary information while maintaining proper vertical rhythm through consistent spacing.

The combination of text sizes, weights, and colors creates clear visual relationships between different pieces of information, guiding users' attention to the most important details first.

<div className="flex justify-between items-start mb-2">
  <h2 className="text-lg font-semibold text-gray-800">{name}</h2>
  <p className="text-lg font-bold text-gray-800">{price}</p>
</div>

Bringing it all together

Let's look at how our final App.js brings everything together to create a working product card. The most important thing to notice is the component structure - instead of putting everything in one file, we've split it into focused components that handle specific tasks.

return (
  <div className="flex justify-center items-center w-screen h-screen">
    <div 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)}
      />
    </div>
  </div>
);

We've also organized the product data into the products array. Here, each product object contains all the information needed for display and interaction.

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...
];

This structure makes it easy to add new products or modify existing ones. You can also easily extend it with new fields like discounts or inventory levels.

The main App component works as a coordinator. It handles all the data and user interactions, then passes them down to the specific components that need them. This means if you need to change how the cart works or update the wishlist feature, you only need to modify the relevant code in one place.

Note: While our example uses static product data, you can easily modify this structure to fetch products from an API. Just update the products array with your API response data, and everything else will work the same way.

Customize the Tailwind theme

In Tailwind CSS v4.0, customizing your theme has become more intuitive with the introduction of the @theme directive. This allows you to define design tokens—such as colors, fonts, spacing, and breakpoints within CSS files.

The @theme directive not only simplifies the customization process but also enhances the flexibility of your design system. For example, defining a new color within the --color-* namespace using @theme automatically generates corresponding utility classes like bg-yourcolor, text-yourcolor, and border-yourcolor. Moreover, all theme variables are exposed as CSS variables, allowing for easy runtime references and facilitating advanced styling techniques.

@import "tailwindcss";
@theme {
  --yourcolor: #36c4c5;
}
export default function CustomComponent() {
  return (
    <div className="text-yourcolor">
      This text uses the custom Tailwind color!
    </div>
  );
}

By centralizing your design tokens within your CSS, you reduce the dependency on external configuration files. This approach aligns with modern CSS practices, enabling developers to leverage CSS variables and custom properties.

Add Tailwind CSS to React frameworks

Tailwind CSS is not limited to React; it also works seamlessly with React frameworks such as Next.js and React Native.

For Next.js, it optimizes style for both static and server-rendered pages. For React Native, Tailwind’s utility classes can be used via NativeWind, which translates Tailwind classes into optimized React Native styles.

Next.js

Tailwind CSS works effortlessly with Next.js, providing a fast and efficient way to style both static and server-rendered pages. Since Next.js supports Server-Side Rendering (SSR) and Static Site Generation (SSG), Tailwind styles are applied at build time, ensuring a faster initial page load and improved SEO.

export default function NextButton() {
  return (
    <button className="px-4 py-2 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 transition">
      Click Me
    </button>
  );
}

Unlike traditional React applications that rely on Client-Side Rendering (CSR), where styles might load after hydration, Next.js ensures that Tailwind styles are immediately available when the page loads. This reduces Cumulative Layout Shifts (CLS) and enhances user experience by preventing unstyled content from appearing momentarily.

Additionally, Tailwind removes all the unused CSS in production- keeping the final CSS file as small as possible, leading to better performance and minimal load times.

React Native

React Native doesn’t support traditional CSS files. Instead, styles are defined using JavaScript objects via the StyleSheet API. This means Tailwind CSS cannot be used directly in React Native applications as it relies on CSS-based styling.

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

export default function NativeButton() {
  return (
    <TouchableOpacity className="px-4 py-2 bg-blue-600 rounded-lg" onPress={() => alert('Button Pressed')}>
      <Text className="text-white font-medium">Click Me</Text>
    </TouchableOpacity>
  );
}

However, NativeWind bridges this gap by bringing Tailwind’s utility-based styling to React Native. It converts Tailwind classes into optimized React Native styles, allowing you to write styles in a familiar class-based format while ensuring they are correctly adapted for mobile platforms.

With NativeWind, you can use modifiers, themes, and platform-specific styles, making it easier to build consistent and adaptable UIs for both iOS and Android while maintaining a clean, scalable styling approach.

While Tailwind CSS focuses on providing utility-first classes rather than pre-designed components, several component libraries have been built on top of it to ease UI development.

Libraries like Flowbite React and Material Tailwind leverage Tailwind's utility classes to create ready-to-use components for React. These libraries offer customizable and responsive components such as buttons, modals, forms, and navigation menus, all styled using Tailwind utilities.

Flowbite React

Flowbite React is a comprehensive component library designed for React and Tailwind CSS, offering a rich set of pre-styled UI elements. It provides a modern, accessible, and responsive component collection, including buttons, modals, tooltips, accordions, tables, and more—all built with Tailwind's utility classes.

One of Flowbite React’s biggest advantages is its modular approach. Each component is designed to be fully customizable, allowing you to extend, modify, or combine components using Tailwind’s utility classes.

Since Flowbite React follows best practices for accessibility, its components come with built-in ARIA attributes, keyboard navigation, and focus management, ensuring an inclusive user experience.

Example of a pop-up modal in Flowbite React:

"use client";

import { Button, Modal } from "flowbite-react";
import { useState } from "react";
import { HiOutlineExclamationCircle } from "react-icons/hi";

export function Component() {
  const [openModal, setOpenModal] = useState(true);

  return (
    <>
      <Button onClick={() => setOpenModal(true)}>Toggle modal</Button>
      <Modal show={openModal} size="md" onClose={() => setOpenModal(false)} popup>
        <Modal.Header />
        <Modal.Body>
          <div className="text-center">
            <HiOutlineExclamationCircle className="mx-auto mb-4 h-14 w-14 text-gray-400 dark:text-gray-200" />
            <h3 className="mb-5 text-lg font-normal text-gray-500 dark:text-gray-400">
              Are you sure you want to delete this product?
            </h3>
            <div className="flex justify-center gap-4">
              <Button color="failure" onClick={() => setOpenModal(false)}>
                {"Yes, I'm sure"}
              </Button>
              <Button color="gray" onClick={() => setOpenModal(false)}>
                No, cancel
              </Button>
            </div>
          </div>
        </Modal.Body>
      </Modal>
    </>
  );
}

Material Tailwind

Material Tailwind is a React-based component library that combines the utility-first styling of Tailwind CSS with Material Design principles. It provides a set of UI components that follow Google's Material Design guidelines while remaining highly customizable through Tailwind utilities.

Unlike traditional Material UI libraries, which often rely on global styles and themes, Material Tailwind fully embraces Tailwind's utility-based styling, allowing developers to adjust components dynamically without overriding styles.

This ensures that design consistency is maintained, while still providing the flexibility to adapt components to project-specific needs.

Example of a pop-up modal in Material Tailwind:

import {
  Card,
  CardHeader,
  CardBody,
  CardFooter,
  Typography,
  Button,
} from "@material-tailwind/react";
 
export function CardDefault() {
  return (
    <Card className="mt-6 w-96">
      <CardHeader color="blue-gray" className="relative h-56">
        <img
          src="https://images.unsplash.com/photo-1540553016722-983e48a2cd10?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=800&q=80"
          alt="card-image"
        />
      </CardHeader>
      <CardBody>
        <Typography variant="h5" color="blue-gray" className="mb-2">
          UI/UX Review Check
        </Typography>
        <Typography>
          The place is close to Barceloneta Beach and bus stop just 2 min by
          walk and near to &quot;Naviglio&quot; where you can enjoy the main
          night life in Barcelona.
        </Typography>
      </CardBody>
      <CardFooter className="pt-0">
        <Button>Read More</Button>
      </CardFooter>
    </Card>
  );
}

Conclusion

In this guide, we explored how to set up and use Tailwind CSS in a React project, covering everything from installation to building an interactive e-commerce product card. We also introduced how Tailwind works with Next.js and React Native, along with Flowbite React and Material Tailwind, two powerful component libraries that speed up development.

By following these steps, you will have a good foundation to start working with Tailwind CSS in React. The best way to improve is through hands-on practice—experiment with different components, customize themes, and build real-world projects to refine your skills.