Follow AiTechWorlds on LinkedIn for professional AI content!Follow Now →
22 minLesson 22 of 40
Tailwind CSS

Building UI Components with Tailwind

Building UI Components with Tailwind

The real power of Tailwind shows when building components. Instead of designing in a stylesheet, you compose visual elements directly in your markup. This lesson covers the most common UI patterns you'll build in every project.

Buttons

Buttons are the most reused element in any UI. Get them right once:

<!-- Primary button -->
<button class="bg-blue-600 hover:bg-blue-700 active:bg-blue-800 text-white font-semibold px-5 py-2.5 rounded-lg transition-colors duration-150">
    Get Started
</button>

<!-- Secondary / outline -->
<button class="border-2 border-blue-600 text-blue-600 hover:bg-blue-50 font-semibold px-5 py-2.5 rounded-lg transition-colors duration-150">
    Learn More
</button>

<!-- Ghost -->
<button class="text-gray-600 hover:text-gray-900 hover:bg-gray-100 font-medium px-4 py-2 rounded-lg transition-colors">
    Cancel
</button>

<!-- Danger -->
<button class="bg-red-600 hover:bg-red-700 text-white font-semibold px-5 py-2.5 rounded-lg transition-colors">
    Delete Account
</button>

<!-- Loading state -->
<button disabled class="bg-blue-600 text-white font-semibold px-5 py-2.5 rounded-lg opacity-75 cursor-not-allowed flex items-center gap-2">
    <svg class="animate-spin h-4 w-4" viewBox="0 0 24 24">
        <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none"/>
        <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/>
    </svg>
    Processing...
</button>

<!-- Icon button -->
<button class="p-2 text-gray-500 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors">
    <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
    </svg>
</button>

In React, extract these as a reusable component:

function Button({ children, variant = "primary", size = "md", disabled, onClick }) {
    const base = "font-semibold rounded-lg transition-colors duration-150 inline-flex items-center gap-2";
    
    const variants = {
        primary: "bg-blue-600 hover:bg-blue-700 text-white",
        secondary: "border-2 border-blue-600 text-blue-600 hover:bg-blue-50",
        ghost: "text-gray-600 hover:text-gray-900 hover:bg-gray-100",
        danger: "bg-red-600 hover:bg-red-700 text-white",
    };
    
    const sizes = {
        sm: "px-3 py-1.5 text-sm",
        md: "px-5 py-2.5",
        lg: "px-6 py-3 text-lg",
    };
    
    return (
        <button
            onClick={onClick}
            disabled={disabled}
            className={`${base} ${variants[variant]} ${sizes[size]} ${disabled ? "opacity-50 cursor-not-allowed" : ""}`}
        >
            {children}
        </button>
    );
}
<nav class="bg-white border-b border-gray-200 sticky top-0 z-50">
    <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div class="flex items-center justify-between h-16">
            
            <!-- Logo -->
            <div class="flex items-center">
                <a href="/" class="text-xl font-bold text-gray-900">
                    MyApp
                </a>
            </div>
            
            <!-- Desktop nav links -->
            <div class="hidden md:flex items-center gap-1">
                <a href="/courses" class="text-gray-600 hover:text-gray-900 hover:bg-gray-100 px-3 py-2 rounded-md text-sm font-medium transition-colors">
                    Courses
                </a>
                <a href="/pricing" class="text-gray-600 hover:text-gray-900 hover:bg-gray-100 px-3 py-2 rounded-md text-sm font-medium transition-colors">
                    Pricing
                </a>
                <a href="/blog" class="text-gray-600 hover:text-gray-900 hover:bg-gray-100 px-3 py-2 rounded-md text-sm font-medium transition-colors">
                    Blog
                </a>
            </div>
            
            <!-- CTA buttons -->
            <div class="hidden md:flex items-center gap-3">
                <a href="/login" class="text-gray-600 hover:text-gray-900 text-sm font-medium transition-colors">
                    Log in
                </a>
                <a href="/signup" class="bg-blue-600 hover:bg-blue-700 text-white text-sm font-semibold px-4 py-2 rounded-lg transition-colors">
                    Get Started
                </a>
            </div>
            
            <!-- Mobile menu button -->
            <button class="md:hidden p-2 text-gray-500 hover:text-gray-900 rounded-lg">
                <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
                </svg>
            </button>
            
        </div>
    </div>
</nav>

Cards

<!-- Basic card -->
<div class="bg-white rounded-xl border border-gray-200 p-6 shadow-sm hover:shadow-md transition-shadow">
    <h3 class="text-lg font-semibold text-gray-900">Card Title</h3>
    <p class="mt-2 text-gray-500 text-sm leading-relaxed">
        Card description text goes here.
    </p>
    <div class="mt-4">
        <a href="#" class="text-blue-600 hover:text-blue-700 text-sm font-medium">
            Read more →
        </a>
    </div>
</div>

<!-- Course card -->
<div class="bg-white rounded-xl overflow-hidden border border-gray-200 hover:border-gray-300 transition-all hover:shadow-lg group">
    <div class="relative">
        <img src="/course.jpg" alt="Course" class="w-full h-44 object-cover group-hover:scale-105 transition-transform duration-300"/>
        <span class="absolute top-3 left-3 bg-blue-600 text-white text-xs font-semibold px-2 py-1 rounded-md">
            Bestseller
        </span>
    </div>
    <div class="p-5">
        <div class="flex items-center gap-2 text-xs text-gray-500 mb-2">
            <span class="bg-blue-50 text-blue-700 px-2 py-0.5 rounded font-medium">React</span>
            <span>•</span>
            <span>24 lessons</span>
        </div>
        <h3 class="font-semibold text-gray-900 leading-snug">
            React Complete Course 2026
        </h3>
        <p class="mt-1 text-sm text-gray-500">
            Build modern web apps with React, hooks, and Next.js
        </p>
        <div class="mt-4 flex items-center justify-between">
            <div class="flex items-center gap-1">
                <span class="text-yellow-400 text-sm">★★★★★</span>
                <span class="text-xs text-gray-500">(2,341)</span>
            </div>
            <span class="text-xl font-bold text-gray-900">$49</span>
        </div>
    </div>
</div>

Forms

<form class="space-y-5 max-w-md">
    
    <!-- Text input -->
    <div>
        <label class="block text-sm font-medium text-gray-700 mb-1.5">
            Full Name
        </label>
        <input 
            type="text" 
            placeholder="Alice Johnson"
            class="w-full border border-gray-300 rounded-lg px-3 py-2.5 text-gray-900 placeholder-gray-400 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 outline-none transition"
        />
    </div>
    
    <!-- Input with error state -->
    <div>
        <label class="block text-sm font-medium text-gray-700 mb-1.5">
            Email
        </label>
        <input 
            type="email" 
            class="w-full border border-red-400 rounded-lg px-3 py-2.5 text-gray-900 focus:border-red-500 focus:ring-2 focus:ring-red-100 outline-none transition"
            value="not-an-email"
        />
        <p class="mt-1 text-sm text-red-600">Please enter a valid email address.</p>
    </div>
    
    <!-- Select -->
    <div>
        <label class="block text-sm font-medium text-gray-700 mb-1.5">
            Role
        </label>
        <select class="w-full border border-gray-300 rounded-lg px-3 py-2.5 text-gray-900 bg-white focus:border-blue-500 focus:ring-2 focus:ring-blue-100 outline-none transition">
            <option>Select a role</option>
            <option>Developer</option>
            <option>Designer</option>
            <option>Manager</option>
        </select>
    </div>
    
    <!-- Textarea -->
    <div>
        <label class="block text-sm font-medium text-gray-700 mb-1.5">
            Message
        </label>
        <textarea 
            rows="4" 
            placeholder="Your message..."
            class="w-full border border-gray-300 rounded-lg px-3 py-2.5 text-gray-900 placeholder-gray-400 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 outline-none transition resize-none"
        ></textarea>
    </div>
    
    <!-- Checkbox -->
    <div class="flex items-start gap-3">
        <input type="checkbox" id="terms" class="mt-0.5 w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"/>
        <label for="terms" class="text-sm text-gray-600">
            I agree to the <a href="#" class="text-blue-600 hover:underline">Terms of Service</a>
        </label>
    </div>
    
    <button type="submit" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2.5 rounded-lg transition-colors">
        Create Account
    </button>
    
</form>

Badges and Tags

<!-- Status badges -->
<span class="bg-green-100 text-green-700 text-xs font-semibold px-2.5 py-0.5 rounded-full">Active</span>
<span class="bg-yellow-100 text-yellow-700 text-xs font-semibold px-2.5 py-0.5 rounded-full">Pending</span>
<span class="bg-red-100 text-red-700 text-xs font-semibold px-2.5 py-0.5 rounded-full">Inactive</span>
<span class="bg-blue-100 text-blue-700 text-xs font-semibold px-2.5 py-0.5 rounded-full">New</span>
<span class="bg-gray-100 text-gray-600 text-xs font-semibold px-2.5 py-0.5 rounded-full">Draft</span>

<!-- Topic tags -->
<div class="flex flex-wrap gap-2">
    <span class="border border-gray-200 text-gray-600 text-xs px-3 py-1 rounded-full hover:border-blue-400 hover:text-blue-600 cursor-pointer transition-colors">
        JavaScript
    </span>
    <span class="border border-gray-200 text-gray-600 text-xs px-3 py-1 rounded-full hover:border-blue-400 hover:text-blue-600 cursor-pointer transition-colors">
        React
    </span>
</div>

Alerts and Notifications

<!-- Success alert -->
<div class="flex items-start gap-3 bg-green-50 border border-green-200 text-green-800 px-4 py-3 rounded-lg">
    <svg class="w-5 h-5 mt-0.5 flex-shrink-0 text-green-600" fill="currentColor" viewBox="0 0 20 20">
        <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
    </svg>
    <div>
        <p class="font-semibold text-sm">Account created!</p>
        <p class="text-sm mt-0.5 text-green-700">Welcome aboard. Check your email to confirm.</p>
    </div>
</div>

<!-- Error alert -->
<div class="flex items-start gap-3 bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded-lg">
    <svg class="w-5 h-5 mt-0.5 flex-shrink-0 text-red-600" fill="currentColor" viewBox="0 0 20 20">
        <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/>
    </svg>
    <p class="text-sm font-medium">Something went wrong. Please try again.</p>
</div>

<!-- Info banner -->
<div class="bg-blue-50 border-l-4 border-blue-500 px-4 py-3">
    <p class="text-sm text-blue-700">
        <span class="font-semibold">Heads up:</span> We'll be doing maintenance on Friday at 2am UTC.
    </p>
</div>
<!-- Overlay + modal -->
<div class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
    <div class="bg-white rounded-2xl shadow-2xl w-full max-w-md">
        
        <!-- Header -->
        <div class="flex items-center justify-between p-6 border-b border-gray-200">
            <h2 class="text-lg font-semibold text-gray-900">Delete Course</h2>
            <button class="p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-lg transition-colors">
                <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
                </svg>
            </button>
        </div>
        
        <!-- Body -->
        <div class="p-6">
            <p class="text-gray-600">
                Are you sure you want to delete <strong>"React Complete Course"</strong>? 
                This action cannot be undone.
            </p>
        </div>
        
        <!-- Footer -->
        <div class="flex items-center justify-end gap-3 p-6 border-t border-gray-200">
            <button class="border border-gray-300 text-gray-700 hover:bg-gray-50 font-medium px-4 py-2 rounded-lg transition-colors">
                Cancel
            </button>
            <button class="bg-red-600 hover:bg-red-700 text-white font-semibold px-4 py-2 rounded-lg transition-colors">
                Delete
            </button>
        </div>
        
    </div>
</div>

Avatar

<!-- Image avatar -->
<img src="/avatar.jpg" alt="Alice" class="w-10 h-10 rounded-full object-cover ring-2 ring-white"/>

<!-- Initial avatar -->
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white font-semibold text-sm">
    AJ
</div>

<!-- Avatar group -->
<div class="flex -space-x-2">
    <img src="/a1.jpg" class="w-8 h-8 rounded-full ring-2 ring-white object-cover"/>
    <img src="/a2.jpg" class="w-8 h-8 rounded-full ring-2 ring-white object-cover"/>
    <img src="/a3.jpg" class="w-8 h-8 rounded-full ring-2 ring-white object-cover"/>
    <div class="w-8 h-8 rounded-full ring-2 ring-white bg-gray-200 flex items-center justify-center text-xs font-medium text-gray-600">
        +4
    </div>
</div>

Empty State

<div class="text-center py-16">
    <div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-4">
        <svg class="w-8 h-8 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
        </svg>
    </div>
    <h3 class="text-gray-900 font-semibold text-lg">No courses yet</h3>
    <p class="text-gray-500 text-sm mt-1 max-w-xs mx-auto">
        Create your first course to get started teaching students.
    </p>
    <button class="mt-6 bg-blue-600 hover:bg-blue-700 text-white font-semibold px-5 py-2.5 rounded-lg transition-colors">
        Create Course
    </button>
</div>

Next lesson: Dark mode and responsive design with Tailwind — building layouts that work everywhere.

📱

Get this course's notes on Telegram!

Free cheat sheets, summaries & practice exercises

Get Notes Free →
!