SuperAPI AI Directory

byted-util-vite-react-tailwind

Frontend & websites

View repository

Updated 10-15 17:30

About this skill

Vite + React + TailwindCSS v4 Development Skill

A guide for front-end project setup and development based on the Vite + React + TailwindCSS v4 + lucide-react tech stack.

Tech Stack

Technology Version Purpose
Vite ^5.x or ^6.x Build tool, development server
React ^18.x or ^19.x UI framework
TailwindCSS ^4.x Atomic CSS framework (Vite plugin mode)
@tailwindcss/vite ^4.x TailwindCSS Vite plugin
lucide-react latest Icon library
TypeScript ^5.x or ^6.x Type safety

Project Initialization

Step 1: Create a Vite + React project

# 创建项目(使用 React + TypeScript 模板)
npm create vite@latest . -- --template react-ts

# 安装依赖
npm install

Step 2: Install TailwindCSS v4

# 安装 TailwindCSS v4 及 Vite 插件
npm install tailwindcss @tailwindcss/vite

Note: v4 no longer requires postcss、autoprefixer, and there is no need to run npx tailwindcss init。

Step 3: Configure the Vite plugin

In vite.config.ts add the @tailwindcss/vite plugin:

vite.config.ts:

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

export default defineConfig({
  plugins: [
    react(),
    tailwindcss(),
  ],
})

Step 4: Clear the default styles and configure CSS (⚠️ mandatory key step)

You must clear all contents of src/index.css and src/App.css Clear all content of, then in src/index.css write only the TailwindCSS import (and optionally @theme):

src/index.css:

@import "tailwindcss";

src/App.css:

/* 清空此文件所有内容,或直接删除此文件 */

🚨 Strictly prohibited: Do not write any index.css in *、body、html and other global selector styles! Including but not limited to:

/* ❌ 以下全部禁止 */
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: ...; -webkit-font-smoothing: antialiased; }
html { scroll-behavior: smooth; }

These global reset styles will override TailwindCSS's preflight (built-in reset), causing spacing, fonts, layout, and other styles to all become abnormal. TailwindCSS v4 already has a complete built-in CSS Reset,no additional global reset is needed or allowed。

The correct index.css contains only:@import "tailwindcss" + optional @theme custom theme variables. Do not write any CSS rules other than these.

v4 uses @import "tailwindcss" to replace v3's @tailwind base; @tailwind components; @tailwind utilities;. No longer need tailwind.config.js configuration file.

Step 5: Install the lucide-react icon library

npm install lucide-react

Step 6: Install utility libraries (if a cn utility function is needed)

# 用于合并 className 的工具库
npm install clsx tailwind-merge

Utility function src/utils/cn.ts:

import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

Step 7: Start the development server

npm run dev

TypeScript Configuration (Important)

Key tsconfig.app.json configuration

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "jsx": "react-jsx",
    "strict": true,
    "verbatimModuleSyntax": false,
    "isolatedModules": true,
    "skipLibCheck": true
  },
  "include": ["src"]
}

⚠️ TypeScript pitfalls you must pay attention to

  1. verbatimModuleSyntax must be set to false

    • When set to true ,import { MyType } from './types' will be retained as a runtime import, but the type does not exist at runtime, causing an error
    • If set to true, then all type imports must use the import type { MyType } syntax, but this is easy to miss
  2. Avoid component names having the same name as imported types

    // ❌ 错误:TaskStats 类型和函数同名,导致 SyntaxError
    import { TaskStats } from '../../types';
    export default function TaskStats(props: { stats: TaskStats }) { ... }
    
    // ✅ 正确:重命名类型导入
    import type { TaskStats as TaskStatsData } from '../../types';
    export default function TaskStats(props: { stats: TaskStatsData }) { ... }
    
  3. Import paths must be accurate

    • Utility function cn is defined in utils/cn.ts, do not import from utils/helpers.ts Import
    • Each utility function should be imported from its correct file path

Development Standards

Project Structure

src/
├── components/        # 可复用组件
│   ├── ui/           # 基础 UI 组件(Button, Card, Input 等)
│   ├── layout/       # 布局组件(Header, Footer, Sidebar 等)
│   └── features/     # 业务功能组件
├── pages/            # 页面组件
├── hooks/            # 自定义 Hooks
├── utils/            # 工具函数
│   ├── cn.ts         # className 合并工具(clsx + tailwind-merge)
│   └── helpers.ts    # 业务工具函数
├── types/            # TypeScript 类型定义
├── mock/             # Mock 数据
│   └── data.ts       # Mock API 数据
├── assets/           # 静态资源
├── App.tsx           # 根组件
├── main.tsx          # 入口文件
└── index.css         # 全局样式(@import "tailwindcss")

Component Development Standards

import { useState } from 'react';
import { Search, Menu, X } from 'lucide-react';

interface HeaderProps {
  title: string;
  onMenuToggle?: () => void;
}

export function Header({ title, onMenuToggle }: HeaderProps) {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <header className="flex items-center justify-between px-6 py-4 bg-white shadow-sm">
      <h1 className="text-xl font-bold text-gray-900">{title}</h1>
      <div className="flex items-center gap-3">
        <Search className="w-5 h-5 text-gray-500" />
        <button
          onClick={() => {
            setIsOpen(!isOpen);
            onMenuToggle?.();
          }}
          className="p-2 rounded-lg hover:bg-gray-100 transition-colors"
        >
          {isOpen ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
        </button>
      </div>
    </header>
  );
}

Local Mock Data

Create src/mock/data.ts to simulate API data:

// src/mock/data.ts
export const mockUsers = [
  { id: 1, name: '张三', email: 'zhangsan@example.com', avatar: '' },
  { id: 2, name: '李四', email: 'lisi@example.com', avatar: '' },
];

// Mock API 函数
export async function fetchMockData<T>(data: T, delay = 500): Promise<T> {
  return new Promise((resolve) => setTimeout(() => resolve(data), delay));
}

Common TailwindCSS patterns

{/* 响应式布局 */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
  {/* 卡片 */}
  <div className="bg-white rounded-xl shadow-md p-6 hover:shadow-lg transition-shadow">
    <h3 className="text-lg font-semibold text-gray-900">标题</h3>
    <p className="mt-2 text-gray-600">描述文字</p>
  </div>
</div>

{/* 按钮样式 */}
<button className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 active:bg-blue-800 transition-colors font-medium">
  主按钮
</button>

{/* 输入框 */}
<input
  type="text"
  placeholder="请输入..."
  className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none"
/>

Icon usage

import {
  Home, Settings, User, Bell, Search,
  ChevronRight, ChevronDown, Plus, Trash2, Edit,
  Check, X, AlertCircle, Info, Loader2
} from 'lucide-react';

// 使用图标
<Home className="w-5 h-5 text-gray-600" />
<Loader2 className="w-5 h-5 animate-spin" />  {/* 加载动画 */}

Self-test verification

After development is complete,muststart the development server and use agent-browser for self-testing:

# 1. 启动开发服务器(后台运行)
npm run dev &

# 2. 等待服务器就绪后,使用 agent-browser 打开页面
agent-browser open http://localhost:5173

# 3. 截取页面快照,检查元素是否正常渲染
agent-browser snapshot -i

# 4. 截图保存,供 QA 参考
agent-browser screenshot --full screenshot.png

# 5. 检查控制台是否有错误
agent-browser eval 'JSON.stringify(window.__errors || "no errors captured")'

# 6. 验证 TailwindCSS 样式是否生效
#    通过 getComputedStyle 检测常见 Tailwind class 是否正确应用
agent-browser eval 'JSON.stringify((() => {
  const checks = [];
  const q = (sel) => document.querySelector(sel);
  const cs = (el) => el ? getComputedStyle(el) : null;

  const flexEl = q(".flex");
  if (flexEl) checks.push({ class: "flex", display: cs(flexEl).display, pass: cs(flexEl).display === "flex" });

  const gridEl = q(".grid");
  if (gridEl) checks.push({ class: "grid", display: cs(gridEl).display, pass: cs(gridEl).display === "grid" });

  const bgEl = q("[class*=\"bg-\"]");
  if (bgEl) checks.push({ class: bgEl.className.match(/bg-\S+/)?.[0], bg: cs(bgEl).backgroundColor, pass: cs(bgEl).backgroundColor !== "rgba(0, 0, 0, 0)" });

  const roundedEl = q("[class*=\"rounded\"]");
  if (roundedEl) checks.push({ class: "rounded", borderRadius: cs(roundedEl).borderRadius, pass: cs(roundedEl).borderRadius !== "0px" });

  const paddingEl = q("[class*=\"p-\"], [class*=\"px-\"], [class*=\"py-\"]");
  if (paddingEl) checks.push({ class: paddingEl.className.match(/p[xy]?-\S+/)?.[0], padding: cs(paddingEl).padding, pass: parseFloat(cs(paddingEl).paddingTop) > 0 || parseFloat(cs(paddingEl).paddingLeft) > 0 });

  const allPass = checks.length > 0 && checks.every(c => c.pass);
  return { tailwindActive: allPass, checksRun: checks.length, details: checks };
})())'

# 7. 验证响应式布局(模拟移动端)
agent-browser close
agent-browser --viewport 375x812 open http://localhost:5173
agent-browser screenshot --full mobile-screenshot.png

# 8. 关闭浏览器
agent-browser close

Self-test checklist:

  • The page has no blank screen, and all components render properly
  • The browser console has no SyntaxError / ReferenceError
  • TailwindCSS styles take effect:tailwindActive: true, and the computedStyle of classes such as flex/grid/bg/rounded/padding matches expectations
  • All interactive features work (click, input, filter, etc.)
  • The responsive layout displays properly on mobile
  • Icons display correctly

Build and preview

# 构建生产版本
npm run build

# 本地预览构建结果
npm run preview

Custom TailwindCSS theme

TailwindCSS v4 uses CSS @theme directives for theme customization, and no longer requires tailwind.config.js:

/* src/index.css */
@import "tailwindcss";

@theme {
  --color-primary-50: #f0f9ff;
  --color-primary-500: #3b82f6;
  --color-primary-600: #2563eb;
  --color-primary-700: #1d4ed8;

  --font-sans: 'Inter', system-ui, sans-serif;
  --font-display: 'your-display-font', sans-serif;
}

Using custom theme variables:

<div className="bg-primary-500 text-white font-display">品牌区域</div>
<p className="text-primary-700 font-sans">正文内容</p>

Notes

  • 🚨 index.css It is strictly forbidden to write *、body、html and other global selector styles in, as these will break TailwindCSS's preflight reset and cause all styles to malfunction.index.css Only @import "tailwindcss" + @theme
  • Use TailwindCSS v4(Vite plugin mode), install tailwindcss and @tailwindcss/vite
  • v4 not required postcss、autoprefixer、tailwind.config.js, and also not required npx tailwindcss init
  • The CSS entry uses @import "tailwindcss" instead of v3's @tailwind directives
  • Theme customization uses CSS @theme directives, instead of tailwind.config.js
  • All icons uniformly use lucide-react; do not mix in other icon libraries
  • Mock data is placed in the src/mock/ directory, making it easy to replace with a real API later
  • Components should preferentially use functional components + TypeScript
  • Follow the design specifications in DESIGN.md for style development
  • verbatimModuleSyntax must be set to false, to avoid runtime errors from type imports
  • When using the cn() utility function, make sure clsx and tailwind-merge
  • After development is complete, you must use agent-browser to start the page for self-test verification