Learn how to use Tailwind CSS and DaisyUI to create beautiful, reusable components for your SaaS.
What You’ll Learn
In this lesson (Days 4-6), you’ll learn:
- Setting up Tailwind CSS in Next.js
- Using DaisyUI for pre-built components
- Building reusable components (Navbar, Footer, Cards)
- Creating forms (Login, Signup)
- Responsive design with Tailwind
- Server vs Client Components
File Structure
03-tailwind-components/
├── app/
│ ├── components/ ← Reusable components
│ │ ├── Navbar.js
│ │ ├── Footer.js
│ │ ├── Hero.js
│ │ ├── FeatureCard.js
│ │ └── PricingCard.js
│ ├── globals.css ← Tailwind imports
│ ├── page.js ← Use components here
│ ├── pricing/
│ │ └── page.js
│ ├── login/
│ │ └── page.js
│ ├── signup/
│ │ └── page.js
│ └── layout.js
├── tailwind.config.js ← Tailwind + DaisyUI config
└── package.json
Why components? Don’t Repeat Yourself (DRY). Create once, use everywhere. Change once, updates everywhere.
Setting Up
cd 03-tailwind-components
npm install
npm run dev
Tailwind CSS Basics
Tailwind uses utility classes instead of writing custom CSS:
Traditional CSS vs Tailwind
// Old way (custom CSS)
<div className="my-custom-class">
// Tailwind way
<div className="bg-blue-500 text-white p-4 rounded-lg">
Common Tailwind Classes
| Class | What it does |
|---|
p-4 | Padding (4 units) |
m-4 | Margin (4 units) |
text-xl | Large text size |
bg-blue-500 | Blue background |
rounded-lg | Rounded corners |
shadow-xl | Box shadow |
flex | Flexbox container |
grid | Grid container |
Tailwind’s spacing scale: p-1 (0.25rem), p-2 (0.5rem), p-4 (1rem), p-8 (2rem), etc.
DaisyUI Components
DaisyUI adds semantic component classes on top of Tailwind:
btn - Styled button
card - Card container
navbar - Navigation bar
hero - Hero section
input - Styled input field
badge - Badge/tag
modal - Modal dialog
Tailwind Configuration
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./app/**/*.{js,ts,jsx,tsx,mdx}',
],
plugins: [require('daisyui')],
daisyui: {
themes: ["light"],
},
}
DaisyUI has 30+ themes! Change "light" to "dark", "cupcake", "cyberpunk", etc.
Building Reusable Components
Navbar Component
Create a navbar you can use on every page:
// Reusable Navbar component
// Uses Tailwind CSS for styling
// DaisyUI provides pre-built component classes
import Link from 'next/link'
export default function Navbar() {
return (
<div className="navbar bg-base-100 shadow-lg">
<div className="navbar-start">
<Link href="/" className="btn btn-ghost text-xl">
🚀 MySaaS
</Link>
</div>
<div className="navbar-center hidden lg:flex">
<ul className="menu menu-horizontal px-1">
<li><Link href="/pricing">Pricing</Link></li>
<li><Link href="/about">About</Link></li>
</ul>
</div>
<div className="navbar-end gap-2">
<Link href="/login" className="btn btn-ghost">
Login
</Link>
<Link href="/signup" className="btn btn-primary">
Sign Up
</Link>
</div>
</div>
)
}
Now use it in any page:
import Navbar from './components/Navbar'
export default function HomePage() {
return (
<div>
<Navbar />
{/* Rest of your page */}
</div>
)
}
Notice the hidden lg:flex class? That hides the menu on mobile and shows it on large screens - instant responsive design!
Server vs Client Components
Next.js 14+ uses React Server Components by default.
Server Components (Default)
// No 'use client' needed
// This runs on the server
export default function HomePage() {
return <div>This is a server component</div>
}
Benefits:
- Faster - runs on the server
- Smaller JavaScript bundle
- Better for SEO
- Can access databases directly
Limitations:
- ❌ No
useState, useEffect
- ❌ No
onClick, onChange
- ❌ No browser APIs
Client Components
'use client'
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
)
}
When to use:
- ✅ Interactive forms
- ✅ Click handlers
- ✅ State management
- ✅ Browser APIs
Only add 'use client' when you actually need interactivity. Keep as much as possible on the server for better performance!
Creating Form Pages
Login Page
'use client'
import { useState } from 'react'
import Link from 'next/link'
import Navbar from '../components/Navbar'
export default function LoginPage() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const handleSubmit = (e) => {
e.preventDefault()
console.log('Login:', email, password)
// Add authentication logic later
}
return (
<div>
<Navbar />
<div className="hero min-h-screen bg-base-200">
<div className="card w-96 bg-base-100 shadow-xl">
<div className="card-body">
<h2 className="card-title text-2xl">Login</h2>
<form onSubmit={handleSubmit}>
<div className="form-control">
<label className="label">
<span className="label-text">Email</span>
</label>
<input
type="email"
className="input input-bordered"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
<div className="form-control mt-4">
<label className="label">
<span className="label-text">Password</span>
</label>
<input
type="password"
className="input input-bordered"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</div>
<button type="submit" className="btn btn-primary w-full mt-6">
Login
</button>
</form>
<p className="text-center mt-4 text-sm">
Don't have an account?{' '}
<Link href="/signup" className="link link-primary">
Sign up
</Link>
</p>
</div>
</div>
</div>
</div>
)
}
This form uses 'use client' because it needs useState and onChange handlers. The Navbar component can still be a server component!
Responsive Design
Tailwind makes responsive design easy with breakpoint prefixes:
<div className="
text-sm {/* Mobile: small text */}
md:text-lg {/* Tablet: large text */}
lg:text-2xl {/* Desktop: extra large text */}
grid-cols-1 {/* Mobile: 1 column */}
md:grid-cols-2 {/* Tablet: 2 columns */}
lg:grid-cols-3 {/* Desktop: 3 columns */}
">
Breakpoints:
sm: - 640px and up
md: - 768px and up
lg: - 1024px and up
xl: - 1280px and up
Try This
Change the theme
Edit tailwind.config.js and change themes: ["light"] to ["dark"] or ["cupcake"]
Add a feature card
Create a new feature card on the home page with an icon and description
Create a contact page
Make app/contact/page.js with a contact form (name, email, message)
Customize the logo
Change the navbar logo emoji to something that fits your SaaS
Add a testimonials section
Create a testimonials section with customer quotes
Dependencies
{
"dependencies": {
"next": "^14.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"daisyui": "^4.4.0"
},
"devDependencies": {
"tailwindcss": "^3.3.0",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.31"
}
}
Common Issues
Tailwind classes not working?
Make sure you imported globals.css in your layout.js and that your tailwind.config.js content paths are correct.
If you need interactivity, add 'use client' at the top of the file. Server components can’t use state or event handlers.
Next Steps
Move to Lesson 4: Auth & Database to add real user authentication and MongoDB database. That’s where things get exciting!