Tailwind CSS with JavaScript Frameworks
Learn how to integrate and use Tailwind CSS effectively with popular JavaScript frameworks like React, Vue, and Angular.
Setting Up Tailwind with JavaScript Frameworks
Tailwind CSS can be integrated with any JavaScript framework. Here's how to set it up with the most popular ones.
General Installation Steps
- Install Tailwind CSS and its dependencies
- Create and configure the Tailwind configuration file
- Set up the build process to process Tailwind directives
- Import the generated CSS into your application
# Install Tailwind CSS and its dependencies
npm install -D tailwindcss postcss autoprefixer
# Create the configuration files
npx tailwindcss init -p
Tailwind CSS with React
Setting Up Tailwind with Create React App
# Create a new React app
npx create-react-app my-app
cd my-app
# Install Tailwind CSS and its dependencies
npm install -D tailwindcss postcss autoprefixer
# Create the configuration files
npx tailwindcss init -p
Configure your tailwind.config.js
:
// tailwind.config.js
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
Add Tailwind directives to your CSS:
/* src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
Import the CSS in your src/index.js
file:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
Using Tailwind with React Components
// Button.jsx - A simple React button component with Tailwind
import React from 'react';
function Button({ children, primary, onClick }) {
const baseClasses = "font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline";
const primaryClasses = "bg-blue-500 hover:bg-blue-700 text-white";
const secondaryClasses = "bg-gray-300 hover:bg-gray-400 text-gray-800";
return (
<button
className={`${baseClasses} ${primary ? primaryClasses : secondaryClasses}`}
onClick={onClick}
>
{children}
</button>
);
}
export default Button;
Using the button component:
// App.jsx
import React from 'react';
import Button from './Button';
function App() {
return (
<div className="container mx-auto p-4">
<h1 className="text-2xl font-bold mb-4">React with Tailwind</h1>
<div className="space-x-4">
<Button primary onClick={() => alert('Primary clicked!')}>
Primary Button
</Button>
<Button onClick={() => alert('Secondary clicked!')}>
Secondary Button
</Button>
</div>
</div>
);
}
export default App;
Conditional Styling in React
// Conditional styling example
function StatusBadge({ status }) {
const statusClasses = {
success: "bg-green-100 text-green-800 border-green-200",
warning: "bg-yellow-100 text-yellow-800 border-yellow-200",
error: "bg-red-100 text-red-800 border-red-200",
info: "bg-blue-100 text-blue-800 border-blue-200"
};
return (
<span className={`px-2 py-1 text-xs font-semibold rounded-full border ${statusClasses[status] || statusClasses.info}`}>
{status.toUpperCase()}
</span>
);
}
Using Tailwind with Next.js
Next.js has built-in support for Tailwind CSS:
# Create a new Next.js project
npx create-next-app my-next-app
cd my-next-app
# Install Tailwind CSS and its dependencies
npm install -D tailwindcss postcss autoprefixer
# Create the configuration files
npx tailwindcss init -p
Configure your tailwind.config.js
:
// tailwind.config.js
module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
Add Tailwind directives to your CSS:
/* styles/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
Import the CSS in your pages/_app.js
file:
// pages/_app.js
import '../styles/globals.css'
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
Tailwind CSS with Vue.js
Setting Up Tailwind with Vue CLI
# Create a new Vue project
vue create my-vue-app
cd my-vue-app
# Install Tailwind CSS and its dependencies
npm install -D tailwindcss postcss autoprefixer
# Create the configuration files
npx tailwindcss init -p
Configure your tailwind.config.js
:
// tailwind.config.js
module.exports = {
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
Create a CSS file with Tailwind directives:
/* src/assets/tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
Import the CSS in your src/main.js
file:
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import './assets/tailwind.css'
createApp(App).mount('#app')
Using Tailwind with Vue Components
<!-- Button.vue - A simple Vue button component with Tailwind -->
<template>
<button
:class="[baseClasses, primary ? primaryClasses : secondaryClasses]"
@click="$emit('click')"
>
<slot></slot>
</button>
</template>
<script>
export default {
name: 'Button',
props: {
primary: {
type: Boolean,
default: false
}
},
data() {
return {
baseClasses: "font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline",
primaryClasses: "bg-blue-500 hover:bg-blue-700 text-white",
secondaryClasses: "bg-gray-300 hover:bg-gray-400 text-gray-800"
}
}
}
</script>
Using the button component:
<!-- App.vue -->
<template>
<div class="container mx-auto p-4">
<h1 class="text-2xl font-bold mb-4">Vue with Tailwind</h1>
<div class="space-x-4">
<Button primary @click="showAlert('Primary clicked!')">
Primary Button
</Button>
<Button @click="showAlert('Secondary clicked!')">
Secondary Button
</Button>
</div>
</div>
</template>
<script>
import Button from './components/Button.vue'
export default {
name: 'App',
components: {
Button
},
methods: {
showAlert(message) {
alert(message)
}
}
}
</script>
Dynamic Classes in Vue
<!-- Dynamic class binding in Vue -->
<template>
<div>
<!-- Using object syntax -->
<div :class="{
'bg-green-100 text-green-800': status === 'success',
'bg-yellow-100 text-yellow-800': status === 'warning',
'bg-red-100 text-red-800': status === 'error',
'bg-blue-100 text-blue-800': status === 'info'
}" class="px-2 py-1 rounded">
{{ message }}
</div>
<!-- Using computed property -->
<div :class="statusClasses" class="mt-4 px-2 py-1 rounded">
{{ message }}
</div>
</div>
</template>
<script>
export default {
props: ['status', 'message'],
computed: {
statusClasses() {
return {
'success': 'bg-green-100 text-green-800',
'warning': 'bg-yellow-100 text-yellow-800',
'error': 'bg-red-100 text-red-800',
'info': 'bg-blue-100 text-blue-800'
}[this.status] || 'bg-gray-100 text-gray-800'
}
}
}
</script>
Using Tailwind with Nuxt.js
# Create a new Nuxt.js project
npx create-nuxt-app my-nuxt-app
cd my-nuxt-app
# Install Tailwind CSS and its dependencies
npm install -D tailwindcss postcss autoprefixer
# Create the configuration files
npx tailwindcss init -p
Configure your tailwind.config.js
:
// tailwind.config.js
module.exports = {
content: [
"./components/**/*.{js,vue,ts}",
"./layouts/**/*.vue",
"./pages/**/*.vue",
"./plugins/**/*.{js,ts}",
"./nuxt.config.{js,ts}",
],
theme: {
extend: {},
},
plugins: [],
}
Create a CSS file with Tailwind directives:
/* assets/css/tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
Update your nuxt.config.js
file:
// nuxt.config.js
export default {
// ...
css: [
'@/assets/css/tailwind.css'
],
build: {
postcss: {
postcssOptions: {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
},
},
}
}
Tailwind CSS with Angular
Setting Up Tailwind with Angular
# Create a new Angular project
ng new my-angular-app
cd my-angular-app
# Install Tailwind CSS and its dependencies
npm install -D tailwindcss postcss autoprefixer
# Create the configuration files
npx tailwindcss init
Configure your tailwind.config.js
:
// tailwind.config.js
module.exports = {
content: [
"./src/**/*.{html,ts}",
],
theme: {
extend: {},
},
plugins: [],
}
Add Tailwind directives to your global styles:
/* src/styles.scss */
@tailwind base;
@tailwind components;
@tailwind utilities;
Configure PostCSS in angular.json
:
// angular.json
{
"projects": {
"my-angular-app": {
"architect": {
"build": {
"options": {
"styles": ["src/styles.scss"],
"stylePreprocessorOptions": {
"includePaths": ["node_modules"]
}
}
}
}
}
}
}
Using Tailwind with Angular Components
// button.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-button',
template: `
<button
[ngClass]="[baseClasses, primary ? primaryClasses : secondaryClasses]"
(click)="onClick.emit($event)"
>
<ng-content></ng-content>
</button>
`
})
export class ButtonComponent {
@Input() primary = false;
@Output() onClick = new EventEmitter<Event>();
baseClasses = "font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline";
primaryClasses = "bg-blue-500 hover:bg-blue-700 text-white";
secondaryClasses = "bg-gray-300 hover:bg-gray-400 text-gray-800";
}
Using the button component:
// app.component.html
<div class="container mx-auto p-4">
<h1 class="text-2xl font-bold mb-4">Angular with Tailwind</h1>
<div class="space-x-4">
<app-button [primary]="true" (onClick)="showAlert('Primary clicked!')">
Primary Button
</app-button>
<app-button (onClick)="showAlert('Secondary clicked!')">
Secondary Button
</app-button>
</div>
</div>
Dynamic Classes in Angular
// status-badge.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-status-badge',
template: `
<span [ngClass]="getStatusClasses()" class="px-2 py-1 text-xs font-semibold rounded-full border">
{{ status.toUpperCase() }}
</span>
`
})
export class StatusBadgeComponent {
@Input() status: 'success' | 'warning' | 'error' | 'info' = 'info';
getStatusClasses() {
const statusClasses = {
'success': 'bg-green-100 text-green-800 border-green-200',
'warning': 'bg-yellow-100 text-yellow-800 border-yellow-200',
'error': 'bg-red-100 text-red-800 border-red-200',
'info': 'bg-blue-100 text-blue-800 border-blue-200'
};
return statusClasses[this.status] || statusClasses.info;
}
}
Best Practices for Using Tailwind with Frameworks
Component Extraction
Extract common UI patterns into reusable components to avoid repetition:
// React example of a reusable Card component
function Card({ title, children, footer }) {
return (
<div className="bg-white rounded-lg shadow-md overflow-hidden">
{title && (
<div className="px-6 py-4 bg-gray-50 border-b">
<h3 className="text-lg font-semibold text-gray-900">{title}</h3>
</div>
)}
<div className="px-6 py-4">
{children}
</div>
{footer && (
<div className="px-6 py-4 bg-gray-50 border-t">
{footer}
</div>
)}
</div>
);
}
Using @apply for Component Styles
For complex components, consider using @apply
in your CSS:
/* styles.css */
@tailwind base;
@tailwind components;
@layer components {
.btn {
@apply font-bold py-2 px-4 rounded;
}
.btn-primary {
@apply bg-blue-500 hover:bg-blue-700 text-white;
}
.btn-secondary {
@apply bg-gray-300 hover:bg-gray-400 text-gray-800;
}
}
@tailwind utilities;
Then use these classes in your components:
// React example
function Button({ children, primary, onClick }) {
return (
<button
className={`btn ${primary ? 'btn-primary' : 'btn-secondary'}`}
onClick={onClick}
>
{children}
</button>
);
}
Organizing Complex Class Lists
For components with many classes, organize them logically:
// React example of organized class lists
function ComplexComponent() {
// Group classes by purpose
const layoutClasses = "flex flex-col md:flex-row items-center justify-between";
const spacingClasses = "p-4 md:p-6 gap-4";
const appearanceClasses = "bg-white rounded-lg shadow-md";
return (
<div className={`${layoutClasses} ${spacingClasses} ${appearanceClasses}`}>
{/* Component content */}
</div>
);
}
Handling Dynamic Classes
Use utility libraries like clsx
or classnames
for complex conditional classes:
// React example with clsx
import clsx from 'clsx';
function DynamicComponent({ isActive, isDisabled, size, variant }) {
const classes = clsx(
// Base classes
'rounded font-semibold',
// Size variants
{
'text-sm px-2 py-1': size === 'small',
'text-base px-4 py-2': size === 'medium',
'text-lg px-6 py-3': size === 'large',
},
// Color variants
{
'bg-blue-500 hover:bg-blue-600 text-white': variant === 'primary',
'bg-gray-200 hover:bg-gray-300 text-gray-800': variant === 'secondary',
'bg-red-500 hover:bg-red-600 text-white': variant === 'danger',
},
// States
{
'ring-2 ring-blue-300': isActive,
'opacity-50 cursor-not-allowed': isDisabled,
}
);
return (
<button className={classes} disabled={isDisabled}>
Button Text
</button>
);
}
Framework-Specific Tailwind Plugins
React-Specific Tools
- twin.macro: Combines Tailwind with CSS-in-JS libraries like Emotion or Styled Components
- tailwind-styled-components: Styled-components with Tailwind classes
- headlessui: Unstyled, accessible UI components that work well with Tailwind
// Example of twin.macro with Emotion
import tw, { styled } from 'twin.macro'
// Using tw prop
const Button = ({ primary, ...props }) => (
<button
css={[
tw`px-4 py-2 rounded`,
primary ? tw`bg-blue-500 text-white` : tw`bg-gray-200 text-gray-800`
]}
{...props}
/>
)
// Using styled
const StyledButton = styled.button`
${tw`px-4 py-2 rounded`}
${({ primary }) => primary ? tw`bg-blue-500 text-white` : tw`bg-gray-200 text-gray-800`}
`
Vue-Specific Tools
- vue-tailwind: A set of Vue components styled with Tailwind CSS
- headlessui-vue: Vue version of Headless UI for accessible components
// Example of vue-tailwind usage
// main.js
import Vue from 'vue'
import VueTailwind from 'vue-tailwind'
const settings = {
't-button': {
component: TButton,
props: {
classes: 'bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded'
}
}
}
Vue.use(VueTailwind, settings)
// In your component
<template>
<t-button>Button</t-button>
</template>
Angular-Specific Tools
- tailwindcss-schematic: Angular schematic for adding Tailwind CSS to an Angular project
- ng-tailwindcss: A CLI tool for integrating Tailwind CSS into Angular projects
# Using tailwindcss-schematic
ng add @ngneat/tailwind
For more Tailwind CSS topics, check out our Fundamentals, Customization, UI Components, Responsive Design, Dark Mode, Performance Optimization, and Animations and Transitions pages.