Build Simple LMS Tools with HTML, JavaScript & Tailwind

By Vandu
Jul 9, 2025

Follow us on


Create lightweight learning management tools like dashboards, assignment systems, and discussion forums using basic web technologies.

Build Simple LMS Tools with HTML, JavaScript & Tailwind

How to Build a Beautiful Course Dashboard UI with Progress Bars

Live Preview

In this tutorial, I'll walk you through creating an elegant, responsive course dashboard UI that displays enrolled courses with progress bars. This interface is perfect for e-learning platforms, online course systems, or any educational application where users need to track their learning progress.

What We're Building

Our course dashboard will include:

  • A statistics overview showing enrolled courses, completed courses, and average progress

  • A grid of course cards with visual progress indicators

  • Filtering and search functionality

  • Responsive design that works on all devices

  • Smooth animations and hover effects

Step 1: Set Up the HTML Structure

First, let's create the basic HTML structure with Tailwind CSS:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Course Dashboard</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body class="bg-gray-50 min-h-screen">
    <div class="container mx-auto px-4 py-8">
        <!-- Content will go here -->
    </div>
</body>
</html>

We're including:

  • Tailwind CSS via CDN

  • Font Awesome for icons

  • A basic responsive container

Step 2: Add the Header Section

<!-- Header -->
<header class="mb-8">
    <h1 class="text-3xl font-bold text-gray-800">My Learning Dashboard</h1>
    <p class="text-gray-600">Track your course progress and continue learning</p>
</header>

This creates a simple header with a title and subtitle.

Step 3: Create Statistics Cards

Let's add three statistics cards showing key metrics:

<!-- Stats Cards -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
    <!-- Enrolled Courses Card -->
    <div class="bg-white rounded-lg shadow p-6">
        <div class="flex items-center">
            <div class="p-3 rounded-full bg-blue-100 text-blue-600 mr-4">
                <i class="fas fa-book-open text-xl"></i>
            </div>
            <div>
                <p class="text-gray-500">Enrolled Courses</p>
                <h3 class="text-2xl font-bold" id="enrolled-count">0</h3>
            </div>
        </div>
    </div>
    
    <!-- Completed Courses Card -->
    <div class="bg-white rounded-lg shadow p-6">
        <div class="flex items-center">
            <div class="p-3 rounded-full bg-green-100 text-green-600 mr-4">
                <i class="fas fa-check-circle text-xl"></i>
            </div>
            <div>
                <p class="text-gray-500">Completed</p>
                <h3 class="text-2xl font-bold" id="completed-count">0</h3>
            </div>
        </div>
    </div>
    
    <!-- Average Progress Card -->
    <div class="bg-white rounded-lg shadow p-6">
        <div class="flex items-center">
            <div class="p-3 rounded-full bg-purple-100 text-purple-600 mr-4">
                <i class="fas fa-chart-line text-xl"></i>
            </div>
            <div>
                <p class="text-gray-500">Avg. Progress</p>
                <h3 class="text-2xl font-bold" id="avg-progress">0%</h3>
            </div>
        </div>
    </div>
</div>

Key features:

  • Responsive grid (1 column on mobile, 3 on desktop)

  • Each card has an icon, label, and value

  • We'll update the values dynamically with JavaScript later

Step 4: Add Filter Controls

<!-- Filter Controls -->
<div class="flex flex-col sm:flex-row justify-between items-center mb-6 gap-4">
    <!-- Search Input -->
    <div class="relative w-full sm:w-64">
        <input type="text" placeholder="Search courses..." 
               class="w-full pl-10 pr-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
        <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
    </div>
    
    <!-- Filter Dropdowns -->
    <div class="flex gap-2 w-full sm:w-auto">
        <select class="px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
            <option>All Categories</option>
            <option>Web Development</option>
            <option>Data Science</option>
            <option>Design</option>
            <option>Business</option>
        </select>
        <select class="px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
            <option>Sort by</option>
            <option>Progress</option>
            <option>Recently Enrolled</option>
            <option>Course Name</option>
        </select>
    </div>
</div>

This adds:

  • A search input with icon

  • Category filter dropdown

  • Sort options dropdown

  • Responsive layout that stacks on mobile

Step 5: Create the Courses Grid

<!-- Courses Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" id="courses-container">
    <!-- Course cards will be dynamically inserted here -->
</div>

<!-- Empty State -->
<div id="empty-state" class="hidden text-center py-12">
    <div class="mx-auto w-24 h-24 bg-gray-100 rounded-full flex items-center justify-center mb-4">
        <i class="fas fa-book text-3xl text-gray-400"></i>
    </div>
    <h3 class="text-xl font-medium text-gray-700 mb-2">No courses enrolled yet</h3>
    <p class="text-gray-500 mb-6">Browse our catalog and start your learning journey today!</p>
    <button class="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition">Explore Courses</button>
</div>

The grid will:

  • Show 1 column on mobile, 2 on tablet, 3 on desktop

  • Include an empty state that shows when no courses exist

Step 6: Add Custom CSS for Animations

Add this inside the <head> section:

<style>
    .progress-bar {
        transition: width 0.5s ease-in-out;
    }
    .course-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
    }
    .course-card {
        transition: all 0.3s ease;
    }
</style>

These styles will:

  • Animate the progress bars when they load

  • Add hover effects to course cards

Step 7: JavaScript Implementation

Now let's add the JavaScript to make it dynamic:

<script>
    // Sample course data
    const courses = [
        {
            id: 1,
            title: "Advanced JavaScript Concepts",
            category: "Web Development",
            instructor: "Sarah Johnson",
            thumbnail: "https://images.unsplash.com/photo-1555066931-4365d14bab8c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=600&q=80",
            progress: 75,
            lastAccessed: "2 days ago",
            totalLessons: 24,
            completedLessons: 18
        },
        // Add more courses as needed...
    ];

    // DOM elements
    const coursesContainer = document.getElementById('courses-container');
    const enrolledCount = document.getElementById('enrolled-count');
    const completedCount = document.getElementById('completed-count');
    const avgProgress = document.getElementById('avg-progress');
    const emptyState = document.getElementById('empty-state');

    // Render courses
    function renderCourses() {
        if (courses.length === 0) {
            emptyState.classList.remove('hidden');
            coursesContainer.classList.add('hidden');
        } else {
            emptyState.classList.add('hidden');
            coursesContainer.classList.remove('hidden');
            
            coursesContainer.innerHTML = '';
            
            courses.forEach(course => {
                const progressColor = getProgressColor(course.progress);
                const isCompleted = course.progress === 100;
                
                const courseCard = document.createElement('div');
                courseCard.className = 'course-card bg-white rounded-xl shadow-md overflow-hidden hover:shadow-lg';
                courseCard.innerHTML = `
                    <div class="relative">
                        <img src="${course.thumbnail}" alt="${course.title}" class="w-full h-48 object-cover">
                        ${isCompleted ? 
                            `<div class="absolute top-2 right-2 bg-green-500 text-white text-xs font-bold px-2 py-1 rounded-full flex items-center">
                                <i class="fas fa-check mr-1"></i> Completed
                            </div>` : ''}
                    </div>
                    <div class="p-6">
                        <div class="flex justify-between items-start mb-2">
                            <span class="inline-block bg-${progressColor}-100 text-${progressColor}-800 text-xs px-2 py-1 rounded-full">
                                ${course.category}
                            </span>
                            <span class="text-sm text-gray-500">${course.lastAccessed}</span>
                        </div>
                        <h3 class="text-xl font-bold text-gray-800 mb-2">${course.title}</h3>
                        <p class="text-gray-600 text-sm mb-4">Instructor: ${course.instructor}</p>
                        
                        <div class="mb-3">
                            <div class="flex justify-between text-sm text-gray-600 mb-1">
                                <span>Progress: ${course.progress}%</span>
                                <span>${course.completedLessons}/${course.totalLessons} lessons</span>
                            </div>
                            <div class="w-full bg-gray-200 rounded-full h-2.5">
                                <div class="progress-bar h-2.5 rounded-full bg-${progressColor}-600" style="width: ${course.progress}%"></div>
                            </div>
                        </div>
                        
                        <div class="flex justify-between mt-4">
                            <button class="text-sm text-blue-600 hover:text-blue-800 font-medium flex items-center">
                                <i class="fas fa-play-circle mr-1"></i> Continue
                            </button>
                            <button class="text-sm text-gray-600 hover:text-gray-800 font-medium flex items-center">
                                <i class="fas fa-info-circle mr-1"></i> Details
                            </button>
                        </div>
                    </div>
                `;
                coursesContainer.appendChild(courseCard);
            });
            
            updateStats();
        }
    }

    // Get appropriate color based on progress
    function getProgressColor(progress) {
        if (progress === 100) return 'green';
        if (progress >= 70) return 'blue';
        if (progress >= 40) return 'purple';
        return 'yellow';
    }

    // Update statistics
    function updateStats() {
        enrolledCount.textContent = courses.length;
        
        const completedCourses = courses.filter(course => course.progress === 100).length;
        completedCount.textContent = completedCourses;
        
        const totalProgress = courses.reduce((sum, course) => sum + course.progress, 0);
        const averageProgress = Math.round(totalProgress / courses.length);
        avgProgress.textContent = `${averageProgress}%`;
    }

    // Initialize
    document.addEventListener('DOMContentLoaded', () => {
        renderCourses();
        
        // Simulate loading animation for progress bars
        setTimeout(() => {
            document.querySelectorAll('.progress-bar').forEach(bar => {
                bar.style.transition = 'width 0.7s ease-in-out';
            });
        }, 100);
    });
</script>

Key JavaScript Functions

  1. renderCourses():

    • Checks if there are courses to display

    • Creates HTML for each course card

    • Applies appropriate styling based on progress

    • Handles the empty state

  2. getProgressColor():

    • Returns different Tailwind color classes based on progress percentage

    • 100% = green, 70-99% = blue, 40-69% = purple, <40% = yellow

  3. updateStats():

    • Calculates and displays:

      • Total enrolled courses

      • Number of completed courses

      • Average progress across all courses

Step 8: Final Touches

The complete implementation includes smooth animations:

  • Progress bars animate when the page loads

  • Course cards have hover effects

  • All transitions are CSS-based for performance


© 2025 Pay18News. All rights reserved.