How to Install Tailwind CSS in Vue.js

Using Tailwind CSS with Vue.js
If you’re building a Vue application, chances are you’ve already felt the friction of managing CSS as your project grows. Reusable components help, but traditional stylesheets still tend to sprawl, duplicate, and slowly become harder to reason about.
Tailwind CSS takes a different approach. Instead of writing custom CSS for every layout and component, you build designs using small, composable utility classes directly in your templates. When paired with Vue’s component model, this workflow feels surprisingly natural.
This guide walks through setting up Tailwind CSS with Vue.js using both modern and legacy tooling. You’ll build real components, learn where people usually get stuck, and see how this stack holds up in real projects.
Table of Content
- Why Tailwind Works So Well with Vue
- Prerequisite
- Method 1: Vue 3 + Vite + Tailwind (Recommended)
- Method 2: Vue CLI + Tailwind (Legacy)
- Building a Real Component
- Common Issues and Fixes
Why Tailwind Works So Well with Vue
Vue components already encourage you to think in small, reusable pieces. Tailwind fits neatly into that mindset.
Everything lives in one place Templates, logic, and styling sit together in a single .vue file. You don’t need to jump between files or remember where a class was defined.
No style collisions Vue components are isolated by design. Combined with Tailwind’s utilities, you avoid most of the specificity and naming problems that show up in larger CSS codebases.
Fast iteration Tweaking spacing, colors, or layout is immediate. Changing ml-2 to ml-4 is faster than editing a stylesheet, recompiling, and checking side effects.
Lean production builds Tailwind scans your Vue files and only includes the utilities you actually use. Even though Tailwind ships with thousands of classes, the final CSS output stays small.
Unlike component libraries that impose visual decisions, Tailwind gives you primitives. You build exactly what your design needs, without fighting default styles.
Prerequisite
Make sure you have the following in place:
- Node.js 18 or newer Node 20 LTS or later is recommended for new projects.
node --version-
npm or yarn: Both work fine.
-
Basic Vue knowledge: You should be comfortable with components, props, and template syntax.
-
A code editor: VS Code with the Volar extension works well for Vue 3 projects.
That’s all you need to get started.
Method 1: Vue 3 + Vite + Tailwind (Recommended)
This is the setup most teams should use today. It’s fast, simple, and officially supported by both Vue and Tailwind.
Step 1: Create a Vue 3 Project
npm create vue@latest my-vue-appcd my-vue-appnpm installVite-based projects start almost instantly, which makes development feel much snappier than older tooling.
Step 2: Install Tailwind CSS
npm install -D tailwindcss postcss autoprefixernpx tailwindcss init -pThis creates:
-
tailwind.config.jsfor customization -
postcss.config.jsfor CSS processing
Step 3: Configure Tailwind
Update tailwind.config.js:
export default { content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"], theme: { extend: {}, }, plugins: [],};The content option tells Tailwind where to look for class names. If Tailwind doesn’t see a class here, it won’t include it in the final build.
Step 4: Add Tailwind Directives
In src/assets/main.css:
@tailwind base;@tailwind components;@tailwind utilities;Then import the file in src/main.js:
import "./assets/main.css";Step 5: Confirm Everything Works
Replace App.vue with:
<template> <div class="flex items-center justify-center min-h-screen bg-linear-to-br from-blue-500 to-purple-600"> <div class="bg-white rounded-2xl shadow-xl p-8 max-w-md"> <h1 class="text-3xl font-bold mb-3">Setup Complete</h1> <p class="text-gray-600"> Tailwind CSS is now working in your Vue project. </p> </div> </div></template>Run the dev server:
npm run devPreview
Setup Complete
Tailwind CSS is now working in your Vue project.
If you see styled content, Tailwind is set up correctly.
Method 2: Vue CLI + Tailwind (Legacy Projects)
Vue CLI is no longer recommended for new projects, but many existing apps still use it.
Step 1: Create or Open a Vue CLI Project
npm install -g @vue/clivue create my-vue-appcd my-vue-appStep 2: Install Tailwind
npm install -D tailwindcss postcss autoprefixernpx tailwindcss init -pStep 3: Configure Content Paths
module.exports = { content: ["./public/**/*.html", "./src/**/*.{vue,js,ts,jsx,tsx}"], theme: { extend: {}, }, plugins: [],};Step 4: Import Tailwind
Create src/assets/tailwind.css:
@tailwind base;@tailwind components;@tailwind utilities;Import it in main.js:
import "./assets/tailwind.css";Run the app with:
npm run serveBuilding a Real Component
Here’s a simple profile card that shows how Tailwind shines in component-based UIs.
You get layout, spacing, typography, hover states, and transitions without writing custom CSS. Everything stays readable and local to the component.
This approach scales well as components grow more complex.
Create src/components/ProfileCard.vue:
<template> <div class="max-w-sm mx-auto bg-white rounded-2xl shadow-lg overflow-hidden hover:shadow-2xl transition-shadow duration-300" > <!-- Header with gradient -->
<div class="h-32 bg-linear-to-r from-indigo-500 via-purple-500 to-pink-500" ></div>
<!-- Profile Image --> <div class="relative px-6 -mt-16"> <img :src="avatar" :alt="name" class="w-32 h-32 rounded-full border-4 border-white shadow-xl" /> </div>
<!-- Content --> <div class="px-6 py-4"> <h2 class="text-2xl font-bold text-gray-900 mb-1"> {{ name }} </h2> <p class="text-gray-600 mb-4"> {{ title }} </p>
<!-- Stats Grid --> <div class="grid grid-cols-3 gap-4 mb-6"> <div class="text-center"> <p class="text-2xl font-bold text-indigo-600">{{ followers }}</p> <p class="text-xs text-gray-500">Followers</p> </div> <div class="text-center"> <p class="text-2xl font-bold text-purple-600">{{ following }}</p> <p class="text-xs text-gray-500">Following</p> </div> <div class="text-center"> <p class="text-2xl font-bold text-pink-600">{{ posts }}</p> <p class="text-xs text-gray-500">Posts</p> </div> </div>
<!-- Action Buttons --> <div class="flex gap-3"> <button class="flex-1 bg-indigo-600 text-white py-2 rounded-lg hover:bg-indigo-700 transition-colors font-semibold" > Follow </button> <button class="flex-1 border-2 border-indigo-600 text-indigo-600 py-2 rounded-lg hover:bg-indigo-50 transition-colors font-semibold" > Message </button> </div> </div> </div></template>
<script>import ProfileCard from './components/ProfileCard.vue'
export default { name: "ProfileCard", props: { name: { type: String, default: "Sarah Johnson", }, title: { type: String, default: "Product Designer", }, avatar: { type: String, default: "https://i.pravatar.cc/150?img=47", }, followers: { type: Number, default: 22397, }, following: { type: Number, default: 500, }, posts: { type: Number, default: 126, }, },};</script>Run your dev server and check the result. You've got a professional-looking profile card with:
Now use it in src/App.vue:
<template> <div class="min-h-screen bg-gray-100 flex items-center justify-center p-4"> <ProfileCard /> </div></template>
<script>import ProfileCard from "./components/ProfileCard.vue";
export default { name: "App", components: { ProfileCard, },};</script>Understanding the Tailwind Classes You Just Used
Let me break down some key patterns:
Responsive Grid
<div class="grid grid-cols-3 gap-4">Creates a 3-column grid with gap spacing. On mobile, you could change this to grid-cols-1 sm:grid-cols-3 to stack vertically on small screens.
Hover States
class="hover:shadow-2xl hover:bg-indigo-700"Applies styles only on hover. Tailwind automatically adds the :hover pseudo-class. Works with focus, active, and other states too.
Transitions
class="transition-colors duration-300"Smoothly animates color changes over 300ms. You can animate shadows, transforms, opacity - anything CSS can transition.
Negative Margins
class="-mt-16"Pulls the avatar up over the header. Negative values work with margin and translate utilities.
Flexbox Utilities
class="flex gap-3"Makes a flex container with spacing between children. Much cleaner than margin hacks. Learn more about these patterns in the official Tailwind documentation.
Customizing Tailwind for Your Project
The default Tailwind theme is great, but you'll want to customize it eventually. Here's how.
Adding Brand Colors
Open tailwind.config.js:
export default { content: [ "./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}", ], theme: { extend: { colors: { 'brand': { 50: '#f0f9ff', 100: '#e0f2fe', 500: '#0ea5e9', 600: '#0284c7', 900: '#0c4a6e', }, }, }, }, plugins: [],}Now use bg-brand-500, text-brand-600, etc. in your components.
Custom Fonts
Import your font in main.css:
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
@tailwind base;@tailwind components;@tailwind utilities;Add it to your config:
theme: { extend: { fontFamily: { 'sans': ['Inter', 'system-ui', 'sans-serif'], }, },}Now font-sans uses Inter globally.
Creating Reusable Component Classes
Sometimes you need a style you'll use in multiple places. Add it to main.css:
@tailwind base;@tailwind components;@tailwind utilities;
@layer components { .btn-primary { @apply bg-indigo-600 text-white px-6 py-2 rounded-lg font-semibold hover:bg-indigo-700 transition-colors; } .card { @apply bg-white rounded-xl shadow-lg p-6; }}Now use <button class="btn-primary"> instead of writing all those utilities every time.
The @layer components directive tells Tailwind to treat these as components, so they work with modifiers like hover: and md:.
Using Tailwind with Vue's Composition API
Sarah Johnson
Product Designer
followers
22k
following
500
posts
126
Customizing Tailwind
Brand Colors
extend: { colors: { brand: { 500: '#0ea5e9', 600: '#0284c7', }, },}Use them like:
<button class="bg-brand-500 text-white">Save</button>Fonts
Import your font in CSS, then register it in tailwind.config.js. From there, utilities like font-sans apply it consistently across your app.
Conditional Styling with Vue Reactivity
Vue’s reactivity pairs well with Tailwind when styles depend on state.
<template> <button :class="[ 'px-4 py-2 rounded-md font-medium transition', isActive ? 'bg-green-600 text-white' : 'bg-gray-200 text-gray-700', ]" @click="isActive = !isActive" > Toggle </button></template>
<script setup>import { ref } from "vue";const isActive = ref(false);</script>This keeps visual state logic close to application logic, which is easier to reason about than switching between CSS and JavaScript.
Reusable Styles Without Losing Tailwind’s Benefits
For patterns you use often, Tailwind supports component classes via @layer.
@layer components { .btn-primary { @apply bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 transition; }}Now your Vue templates stay readable:
<button class="btn-primary">Save changes</button>This strikes a good balance between utility classes and reuse.
Tailwind with Vue Router
Navigation states are easy to handle with Tailwind.
<router-link to="/settings" class="px-3 py-2 text-gray-600 hover:text-gray-900" active-class="text-indigo-600 font-semibold"> Settings</router-link>You don’t need custom CSS for active states—Vue Router and Tailwind handle it cleanly.
Common Issues and Fixes
Classes not applying: Check content paths and restart the dev server
Custom styles missing: Tailwind config changes always require a restart
Production styles missing: Content paths don’t match actual file locations
Most issues come down to configuration or stale dev servers.
Component Libraries That Pair Well
Headless UI – Unstyled, accessible primitives
Flowbite Vue – Ready-made Tailwind components
DaisyUI – Semantic component classes
Radix Vue – Accessible building blocks
These save time without locking you into rigid designs.
You now know how to set up Tailwind CSS with Vue.js using either Vite (recommended) or Vue CLI. You've built real components and learned how to customize everything. The combination of Vue's reactivity and Tailwind's utilities is incredibly productive once you get used to it. You'll prototype faster, maintain cleaner code, and ship smaller CSS bundles.
Tailwind CSS and Vue.js form a practical, efficient pairing. You get fast iteration, predictable styling, and smaller CSS bundles, all while keeping components easy to reason about.
Once the workflow clicks, it’s hard to go back to traditional CSS's heavy setups. For most Vue projects today, this combination is a solid default.
Windframe is an AI visual editor for rapidly building stunning web UIs & websites
Start building stunning web UIs & websites!
