When I built an AI-powered chatbot for my portfolio using React, Vite, and Tailwind CSS v4, everything worked beautifully — until deployment.
Once I pushed to Vercel, the build crashed hard.
The cause?
👉 Mixing Tailwind CSS v3 and v4 components in the same project.
Here’s what happened, what I learned, and how I fixed it.
📋 Table of Contents
- The Setup: What I Was Building
- The Mistake: Installing @tailwindcss/typography
- Why It Worked Locally But Failed on Vercel
- The Root Cause: Version Conflicts
- The Solution: Clean Migration to v4
- Custom Typography: Better Than the Plugin
- Complete Setup Guide
- Key Takeaways
🚀 The Setup: What I Was Building
I was creating an AI chatbot for my portfolio with these features:
- Frontend: React 18 + Vite 6
- Styling: Tailwind CSS v4
- AI Integration: Groq API (Llama 3.1 70B Versatile)
-
Markdown Rendering:
react-markdown+remark-gfm - Deployment: Vercel
The chatbot needed to render AI messages with bold, italics, code blocks, lists, and links — so I reached for @tailwindcss/typography.
❌ The Mistake: Installing @tailwindcss/typography
I ran this:
npm install @tailwindcss/typography
Then updated my component:
{isBot ? (
<div className="prose prose-invert prose-sm md:prose-base">
<ReactMarkdown remarkPlugins={[remarkGfm]}>
{message.text}
</ReactMarkdown>
</div>
) : (
<div className="text-sm md:text-base">{message.text}</div>
)}
Locally, everything worked perfectly.
AI responses looked clean and styled — until Vercel rejected the build.
🤔 Why It Worked Locally But Failed on Vercel
Locally, the dev server was lenient:
- Vite dev server ignores strict dependency rules
- Cached dependencies hid conflicts
- Development builds don’t tree-shake or optimize
But Vercel’s production build was strict:
Error: The `@tailwindcss/typography` plugin is designed for Tailwind CSS v3.x
but you are using Tailwind CSS v4.x. These versions are incompatible.
Vercel installs fresh dependencies and performs strict checks — so it caught what local dev ignored.
🔍 The Root Cause: Version Conflicts
In package.json, I had:
"devDependencies": {
"tailwindcss": "^4.1.14"
}
But running this:
npm list tailwindcss
Revealed this:
├── tailwindcss@4.1.14
└─┬ @tailwindcss/typography@0.5.10
└── tailwindcss@3.4.1 ← Hidden dependency!
The typography plugin pulled in Tailwind v3, creating a version conflict.
| Feature | Tailwind v3 | Tailwind v4 |
|---|---|---|
| Config | tailwind.config.js |
CSS-first (@import "tailwindcss") |
| PostCSS | Required | Optional (@tailwindcss/vite) |
| Plugins | JS config | CSS or standalone packages |
| Build | PostCSS | Vite-native |
Mixing both leads to:
- ⚠️ Conflicting PostCSS transforms
- ⚠️ Duplicate utility generation
- ⚠️ Broken configuration detection
- ⚠️ Build failures
✅ The Solution: Clean Migration to v4
Step 1: Remove v3 Dependencies
npm uninstall @tailwindcss/typography postcss autoprefixer
rm tailwind.config.js postcss.config.js
Step 2: Verify a Clean v4 Setup
Your package.json should include only:
"devDependencies": {
"tailwindcss": "^4.1.14",
"@tailwindcss/vite": "^4.1.14",
"vite": "^6.0.5",
"@vitejs/plugin-react": "^4.3.4"
}
Step 3: Update Vite Config
// 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: Clean CSS Import
/* src/index.css */
@import "tailwindcss";
/* No need for @tailwind base; etc. */
Step 5: Reinstall Everything
rm -rf node_modules package-lock.json
npm install
🎨 Custom Typography: Better Than the Plugin
Instead of using the plugin, I built my own lightweight typography system — fully compatible with v4, more customizable, and no dependency conflicts.
Example: src/index.css
@import "tailwindcss";
.markdown-prose {
line-height: 1.75;
color: rgb(229 231 235);
}
.markdown-prose a {
color: rgb(34 211 238);
text-decoration: none;
transition: color 0.2s;
}
.markdown-prose a:hover {
text-decoration: underline;
color: rgb(6 182 212);
}
.markdown-prose code {
background: rgba(255,255,255,0.1);
padding: 0.25rem 0.5rem;
border-radius: 0.375rem;
font-family: 'Courier New', monospace;
color: rgb(249 168 212);
}
.markdown-prose pre {
background: rgba(0,0,0,0.3);
border-radius: 0.5rem;
padding: 1rem;
overflow-x: auto;
}
Component Update:
<div className="markdown-prose">
<ReactMarkdown remarkPlugins={[remarkGfm]}>
{message.text}
</ReactMarkdown>
</div>
🧩 Complete Setup Guide
1. Install Dependencies
npm install react react-dom react-markdown remark-gfm
npm install -D vite @vitejs/plugin-react tailwindcss @tailwindcss/vite
2. Project Structure
my-project/
├── src/
│ ├── index.css
│ ├── main.tsx
│ └── components/
│ └── ChatBot.tsx
├── vite.config.ts
└── package.json
3. Test for Conflicts
npm list tailwindcss
✅ Only v4 should appear
🎯 Key Takeaways
💡 What I Learned
- Local ≠ Production – Always test production builds locally.
- Peer Dependencies Matter –
npm list <package>is your friend. - Tailwind v4 ≠ v3 – It’s a full architecture shift.
- Custom CSS Wins – Fewer dependencies, cleaner builds.
- Vercel Is Strict – And that’s a good thing.
✅ Do
- Test production builds before deploy
- Read plugin compatibility docs
- Keep dependencies minimal
❌ Don’t
- Mix v3 and v4 packages
- Ignore peer dependency warnings
- Assume local dev = production ready
🔗 Resources
💬 Final Thoughts
Mixing Tailwind v3 and v4 is like trying to run diesel in an electric car — they’re built differently.
By going all-in with Tailwind v4 and replacing the typography plugin, I ended up with:
- ⚡ Faster builds
- 🎨 Fully custom styles
- 🚀 100% production compatibility
- 🔧 Easier maintenance
If you’re upgrading — migrate cleanly, don’t mix.
🙋♂️ Questions?
Found this helpful? Drop a comment or connect with me:
🌍 Connect with Me
- 🧑💻 GitHub
- 🪄 [Portfolio]— Under Contruction 🚧
- 🐦 X (Twitter)
- ✉️ wishotstudio@gmail.com
Last updated: October 2024
Tailwind CSS: v4.1.14 • React: 18.3.1 • Vite: 6.0.5

