# Vite Tailwind Configuration Not Working? Fix Missing Styles in React Projects

> Fix Vite Tailwind CSS not applying styles in your React project. Learn how to resolve missing Tailwind plugin registration and CSS import issues for correct styling.

- Repository: [Vite/vite](https://github.com/vitejs/vite)
- Tags: how-to-guide
- Published: 2026-02-21

---

**The most common reason Tailwind styles fail to apply in a Vite React project is missing the `@tailwindcss/vite` plugin registration in [`vite.config.ts`](https://github.com/vitejs/vite/blob/main/vite.config.ts), followed by failing to import the CSS entry file containing the `@tailwind` directives in your [`main.jsx`](https://github.com/vitejs/vite/blob/main/main.jsx) or [`main.tsx`](https://github.com/vitejs/vite/blob/main/main.tsx) entry point.**

When integrating Tailwind CSS with Vite in a React application, the vite tailwind configuration requires precise coordination between multiple files. According to the `vitejs/vite` repository source code, the integration relies on the official `@tailwindcss/vite` plugin working alongside a standard PostCSS pipeline. If any link in this chain breaks, your utility classes will render as plain text without styling.

## Common Causes for Vite Tailwind Configuration Failures

### Missing Tailwind CSS Import in Entry Files

The generated CSS file (typically [`index.css`](https://github.com/vitejs/vite/blob/main/index.css)) must contain the Tailwind directives and be imported into your application's entry point. In [`playground/tailwind/src/main.jsx`](https://github.com/vitejs/vite/blob/main/playground/tailwind/src/main.jsx), the entry file explicitly imports the CSS:

```jsx
import './index.css'  // Required for Tailwind utilities to load

```

Without this import, the Tailwind plugin processes the CSS but Vite never includes it in the module graph, so the browser receives no utility classes.

### @tailwindcss/vite Plugin Not Registered

The Tailwind plugin must be explicitly added to the `plugins` array in [`vite.config.ts`](https://github.com/vitejs/vite/blob/main/vite.config.ts). As shown in [`playground/tailwind/vite.config.ts`](https://github.com/vitejs/vite/blob/main/playground/tailwind/vite.config.ts):

```ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
    react(),
    tailwindcss(),  // Crucial for processing @tailwind directives
  ],
})

```

If this plugin is omitted, Vite passes CSS files through unchanged, leaving the `@tailwind` directives unprocessed and invalid in the browser.

### Incorrect Content Paths in tailwind.config.ts

Tailwind's purge scanner relies on the `content` configuration to know which files contain utility classes. In [`playground/tailwind/tailwind.config.ts`](https://github.com/vitejs/vite/blob/main/playground/tailwind/tailwind.config.ts), the configuration explicitly includes React source files:

```ts
export default {
  content: ['./src/**/*.{js,jsx,ts,tsx,vue}'],  // Must cover your React components
  theme: {
    extend: {},
  },
  plugins: [],
}

```

If these paths are misconfigured or too narrow, Tailwind generates an empty CSS file in production, removing all utilities during the purge step.

### CSS File Loaded Before Dev Server Processing Completes

In development mode, Vite may serve [`index.css`](https://github.com/vitejs/vite/blob/main/index.css) before the Tailwind plugin finishes processing, resulting in partially generated or empty CSS. The `vitejs/vite` repository includes a `delayIndexCssPlugin` in [`playground/tailwind/vite.config.ts`](https://github.com/vitejs/vite/blob/main/playground/tailwind/vite.config.ts) that demonstrates this fix:

```ts
function delayIndexCssPlugin(): Plugin {
  let server
  return {
    name: 'delay-index-css',
    enforce: 'pre',
    configureServer(_server) {
      server = _server
    },
    async load(id) {
      if (server && id.includes('index.css')) {
        await server.waitForRequestsIdle(id)  // Wait for processing to complete
      }
    },
  }
}

```

This plugin ensures the CSS is only served after Tailwind has finished generating all utilities.

### Missing PostCSS Configuration

Tailwind requires PostCSS to resolve `@import` statements and process `@tailwind` directives. The [`playground/tailwind/postcss.config.js`](https://github.com/vitejs/vite/blob/main/playground/tailwind/postcss.config.js) file shows the required setup:

```js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

```

Without this configuration file, or if it is misnamed (e.g., [`postcss.config.ts`](https://github.com/vitejs/vite/blob/main/postcss.config.ts) without proper ES module handling), the PostCSS step will skip Tailwind processing.

## How Vite Integrates Tailwind CSS

Understanding the processing flow helps diagnose where your vite tailwind configuration breaks:

1. **Plugin Registration**: [`vite.config.ts`](https://github.com/vitejs/vite/blob/main/vite.config.ts) loads `@tailwindcss/vite` into the plugin array, hooking into Vite's CSS processing pipeline.

2. **CSS Import Trigger**: When your React entry file (e.g., [`src/main.jsx`](https://github.com/vitejs/vite/blob/main/src/main.jsx)) imports [`./index.css`](https://github.com/vitejs/vite/blob/main/./index.css), Vite processes the file through the plugin pipeline.

3. **Tailwind Compilation**: The plugin hands the CSS to Tailwind's compiler, which reads [`tailwind.config.ts`](https://github.com/vitejs/vite/blob/main/tailwind.config.ts) to determine which utilities to generate based on the `content` paths.

4. **PostCSS Processing**: The CSS runs through PostCSS (configured in [`postcss.config.js`](https://github.com/vitejs/vite/blob/main/postcss.config.js)) to handle autoprefixing and other transformations.

5. **Dev Server Delivery**: In development, Vite serves the processed CSS via HMR. The `delayIndexCssPlugin` pattern ensures the file isn't served prematurely.

If any step fails—missing plugin, unimported CSS, or incorrect content paths—the chain breaks and styles disappear.

## Step-by-Step Vite Tailwind Configuration Setup

### Configure vite.config.ts

Register both the React plugin and the Tailwind plugin. Based on [`playground/tailwind/vite.config.ts`](https://github.com/vitejs/vite/blob/main/playground/tailwind/vite.config.ts):

```ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
    react(),
    tailwindcss(),  // Required for processing @tailwind directives
  ],
})

```

### Configure tailwind.config.ts

Point Tailwind to your React component files. This example from [`playground/tailwind/tailwind.config.ts`](https://github.com/vitejs/vite/blob/main/playground/tailwind/tailwind.config.ts) covers JSX and TSX files:

```ts
import type { Config } from 'tailwindcss'

export default {
  content: ['./src/**/*.{js,jsx,ts,tsx,vue}'],  // Critical: must match your file structure
  theme: {
    extend: {},
  },
  plugins: [],
} satisfies Config

```

### Configure postcss.config.js

Ensure PostCSS processes Tailwind. As shown in [`playground/tailwind/postcss.config.js`](https://github.com/vitejs/vite/blob/main/playground/tailwind/postcss.config.js):

```js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

```

### Create the CSS Entry File

Create [`src/index.css`](https://github.com/vitejs/vite/blob/main/src/index.css) with the Tailwind directives. From [`playground/tailwind/index.css`](https://github.com/vitejs/vite/blob/main/playground/tailwind/index.css):

```css
@tailwind base;
@tailwind components;
@tailwind utilities;

```

### Import CSS in Your React Entry Point

Import the CSS file in [`src/main.jsx`](https://github.com/vitejs/vite/blob/main/src/main.jsx) or [`src/main.tsx`](https://github.com/vitejs/vite/blob/main/src/main.tsx). This pattern from [`playground/tailwind/src/main.jsx`](https://github.com/vitejs/vite/blob/main/playground/tailwind/src/main.jsx) ensures the CSS enters Vite's module graph:

```jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.css'  // Required: imports Tailwind-processed CSS

function App() {
  return <div className="bg-blue-500 text-white p-4">Hello Tailwind!</div>
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />)

```

## Troubleshooting: Fixing Missing Tailwind Styles

If your vite tailwind configuration still shows no styles after setup, implement the delay plugin pattern from the `vitejs/vite` playground:

```ts
function delayIndexCssPlugin(): Plugin {
  let server
  return {
    name: 'delay-index-css',
    enforce: 'pre',
    configureServer(_server) {
      server = _server
    },
    async load(id) {
      if (server && id.includes('index.css')) {
        await server.waitForRequestsIdle(id)  // Ensures Tailwind processing completes
      }
    },
  }
}

```

Add this plugin to [`vite.config.ts`](https://github.com/vitejs/vite/blob/main/vite.config.ts) before the Tailwind plugin:

```ts
export default defineConfig({
  plugins: [
    delayIndexCssPlugin(),  // Add this first
    react(),
    tailwindcss(),
  ],
})

```

This resolves race conditions where Vite serves the CSS file before the Tailwind compiler finishes generating utility classes.

## Summary

- **Vite does not include Tailwind by default**—you must install and register the `@tailwindcss/vite` plugin in [`vite.config.ts`](https://github.com/vitejs/vite/blob/main/vite.config.ts).
- **The CSS entry file must be imported** in your React entry point (e.g., [`src/main.jsx`](https://github.com/vitejs/vite/blob/main/src/main.jsx)) to enter Vite's module graph; the Tailwind plugin only processes imported files.
- **Content paths must match your file structure** in [`tailwind.config.ts`](https://github.com/vitejs/vite/blob/main/tailwind.config.ts)—incorrect globs cause Tailwind to purge all utilities in production.
- **PostCSS configuration is required** to resolve `@tailwind` directives; ensure [`postcss.config.js`](https://github.com/vitejs/vite/blob/main/postcss.config.js) exists and loads the Tailwind plugin.
- **Development race conditions** can be fixed using the `delayIndexCssPlugin` pattern from the `vitejs/vite` playground, which waits for the server to idle before serving CSS.

## Frequently Asked Questions

### Why are my Tailwind classes working in development but missing in production builds?

This typically occurs when the `content` configuration in [`tailwind.config.ts`](https://github.com/vitejs/vite/blob/main/tailwind.config.ts) does not include the correct file paths for your React components. During development, Tailwind generates all utilities on-demand, but in production, it purges unused styles based on the `content` globs. If your JSX or TSX files are not covered by the glob pattern (e.g., `./src/**/*.{js,jsx,ts,tsx}`), Tailwind removes all utility classes, resulting in an empty CSS file in the production bundle.

### Do I need both the @tailwindcss/vite plugin and a postcss.config.js file?

Yes, both are necessary for a complete vite tailwind configuration. The `@tailwindcss/vite` plugin integrates Tailwind into Vite's build pipeline and handles hot module replacement (HMR) during development. However, Tailwind still requires PostCSS to process the `@tailwind` directives and handle autoprefixing. The [`postcss.config.js`](https://github.com/vitejs/vite/blob/main/postcss.config.js) file ensures that when Vite processes CSS files, PostCSS runs the Tailwind compiler. Without the PostCSS config, the `@tailwind` directives remain unprocessed in the final CSS.

### Where should I import the Tailwind CSS file in a React project?

Import the CSS file in your application's JavaScript or TypeScript entry point, typically [`src/main.jsx`](https://github.com/vitejs/vite/blob/main/src/main.jsx) or [`src/main.tsx`](https://github.com/vitejs/vite/blob/main/src/main.tsx). This import statement (e.g., `import './index.css'`) ensures the CSS file enters Vite's module graph. The `@tailwindcss/vite` plugin only processes CSS files that are imported through the module system; if you link the CSS directly in your [`index.html`](https://github.com/vitejs/vite/blob/main/index.html) without importing it in your JS entry, the Tailwind compiler may not process the file correctly during the build, or HMR may fail in development.

### What is the delayIndexCssPlugin and when do I need it?

The `delayIndexCssPlugin` is a custom Vite plugin demonstrated in the `vitejs/vite` playground that prevents race conditions during development. It delays serving the [`index.css`](https://github.com/vitejs/vite/blob/main/index.css) file until Vite's dev server has finished processing all pending requests (`server.waitForRequestsIdle`). You need this plugin if you experience intermittent missing styles during hot module replacement (HMR) or if the CSS file appears to load before Tailwind finishes generating utility classes. This is particularly useful in larger React projects where the Tailwind compiler may take longer to process the `content` paths.