Step-by-Step Guide to Building a Beautiful Assignment Submission Form with HTML, CSS, JS, and Tailwind CSS
In this tutorial, we'll create a responsive and interactive Assignment Submission Form that allows users to upload files and submit text answers. We'll use HTML, CSS, JavaScript, and Tailwind CSS for styling.
Final Output Preview
Live Demo |
Step 1: Set Up the HTML Structure
We start with a basic HTML template and include Tailwind CSS for styling.
HTML Boilerplate with Tailwind
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Assignment Submission Form</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 max-w-3xl">
<!-- Form will go here -->
</div>
</body>
</html>
Key Elements:
-
container mx-auto
: Centers the form. -
bg-gray-50
: Light background for better readability. -
max-w-3xl
: Limits form width for better UX.
Step 2: Create the Form Layout
We’ll structure the form with:
-
Header (Title, due date, course info)
-
Progress Bar (Shows submission completion)
-
Student Info Fields (Name, ID)
-
Text Answer Section (Textarea for answers)
-
File Upload Section (Drag & drop)
-
Terms Checkbox (Confirmation)
-
Submit Button
Form Structure
<div class="bg-white rounded-xl shadow-md overflow-hidden p-6 md:p-8">
<!-- Header -->
<div class="text-center mb-8">
<h1 class="text-2xl md:text-3xl font-bold text-gray-800 mb-2">Assignment Submission</h1>
<p class="text-gray-600">Submit your files and answers before the deadline</p>
<div class="mt-4 flex items-center justify-center space-x-2">
<span class="px-3 py-1 bg-blue-100 text-blue-800 rounded-full text-sm font-medium">Due: June 15, 2023</span>
<span class="px-3 py-1 bg-purple-100 text-purple-800 rounded-full text-sm font-medium">CS-101</span>
</div>
</div>
<!-- Progress Bar -->
<div class="mb-8">
<div class="flex justify-between mb-2">
<span class="text-sm font-medium text-gray-700">Submission Progress</span>
<span class="text-sm font-medium text-gray-500" id="progress-text">0%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div class="bg-blue-600 h-2.5 rounded-full progress-bar" style="width: 0%"></div>
</div>
</div>
<!-- Student Info -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label for="name" class="block text-sm font-medium text-gray-700 mb-1">Full Name</label>
<input type="text" id="name" name="name" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition" placeholder="John Doe">
</div>
<div>
<label for="student-id" class="block text-sm font-medium text-gray-700 mb-1">Student ID</label>
<input type="text" id="student-id" name="student-id" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition" placeholder="12345678">
</div>
</div>
<!-- Text Answer -->
<div class="mt-6">
<label for="answer" class="block text-sm font-medium text-gray-700 mb-1">Assignment Answer</label>
<textarea id="answer" name="answer" rows="5" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition" placeholder="Write your answer here..."></textarea>
<p class="mt-1 text-sm text-gray-500">Minimum 200 words required.</p>
</div>
<!-- File Upload -->
<div class="mt-6">
<label class="block text-sm font-medium text-gray-700 mb-2">Upload Files</label>
<div class="file-upload bg-gray-50 border-2 border-dashed border-gray-300 rounded-lg p-6 text-center cursor-pointer hover:bg-gray-100 transition" id="drop-zone">
<input type="file" id="file-input" class="hidden" multiple>
<div class="flex flex-col items-center justify-center space-y-2">
<i class="fas fa-cloud-upload-alt text-3xl text-blue-500"></i>
<p class="text-sm text-gray-600"><span class="font-medium text-blue-600">Click to upload</span> or drag and drop</p>
<p class="text-xs text-gray-500">PDF, DOCX, PPT, JPG, PNG (Max. 10MB each)</p>
</div>
</div>
<div class="mt-4 space-y-2" id="file-list"></div>
</div>
<!-- Terms Checkbox -->
<div class="mt-6 flex items-start">
<div class="flex items-center h-5">
<input id="terms" name="terms" type="checkbox" required class="w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-blue-300">
</div>
<label for="terms" class="ml-3 text-sm font-medium text-gray-700">I confirm that this is my own work and complies with academic integrity policies.</label>
</div>
<!-- Submit Button -->
<div class="mt-6 pt-2">
<button type="submit" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-4 rounded-lg transition duration-300 flex items-center justify-center">
<i class="fas fa-paper-plane mr-2"></i> Submit Assignment
</button>
</div>
</div>
Step 3: Add Custom CSS for File Upload
We need some custom CSS to style the file upload area.
CSS Styling
<style>
.file-upload {
position: relative;
overflow: hidden;
}
.file-upload input[type="file"] {
position: absolute;
top: 0;
right: 0;
min-width: 100%;
min-height: 100%;
opacity: 0;
cursor: pointer;
}
.progress-bar {
transition: width 0.3s ease;
}
.file-item:hover .file-remove {
opacity: 1;
}
</style>
Step 4: Add JavaScript for Interactivity
We’ll implement:
-
Drag & Drop File Upload
-
File Preview & Removal
-
Progress Bar Updates
-
Form Submission Handling
JavaScript Code
<script>
document.addEventListener('DOMContentLoaded', function() {
const dropZone = document.getElementById('drop-zone');
const fileInput = document.getElementById('file-input');
const fileList = document.getElementById('file-list');
const form = document.getElementById('submission-form');
const progressBar = document.querySelector('.progress-bar');
const progressText = document.getElementById('progress-text');
const successModal = document.getElementById('success-modal');
let files = [];
// Handle drag and drop
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
// Highlight drop zone
['dragenter', 'dragover'].forEach(eventName => {
dropZone.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, unhighlight, false);
});
function highlight() {
dropZone.classList.add('border-blue-500', 'bg-blue-50');
}
function unhighlight() {
dropZone.classList.remove('border-blue-500', 'bg-blue-50');
}
// Handle dropped files
dropZone.addEventListener('drop', handleDrop, false);
fileInput.addEventListener('change', function() {
handleFiles(this.files);
});
function handleDrop(e) {
const dt = e.dataTransfer;
const newFiles = dt.files;
handleFiles(newFiles);
}
function handleFiles(newFiles) {
files = [...files, ...newFiles];
updateFileList();
updateProgress();
}
// Update file list display
function updateFileList() {
fileList.innerHTML = '';
if (files.length === 0) {
fileList.innerHTML = '<p class="text-sm text-gray-500 text-center py-4">No files selected</p>';
return;
}
files.forEach((file, index) => {
const fileItem = document.createElement('div');
fileItem.className = 'file-item flex items-center justify-between bg-gray-50 p-3 rounded-lg';
const fileInfo = document.createElement('div');
fileInfo.className = 'flex items-center space-x-3';
const fileIcon = document.createElement('i');
fileIcon.className = getFileIcon(file.type) + ' text-blue-500';
const fileName = document.createElement('span');
fileName.className = 'text-sm font-medium text-gray-700 truncate max-w-xs';
fileName.textContent = file.name;
const fileSize = document.createElement('span');
fileSize.className = 'text-xs text-gray-500';
fileSize.textContent = formatFileSize(file.size);
fileInfo.appendChild(fileIcon);
fileInfo.appendChild(fileName);
const fileActions = document.createElement('div');
fileActions.className = 'flex items-center space-x-2';
const fileRemove = document.createElement('button');
fileRemove.className = 'file-remove text-red-500 hover:text-red-700 opacity-0 hover:opacity-100 transition';
fileRemove.innerHTML = '<i class="fas fa-times"></i>';
fileRemove.onclick = (e) => {
e.preventDefault();
files.splice(index, 1);
updateFileList();
updateProgress();
};
fileActions.appendChild(fileRemove);
fileItem.appendChild(fileInfo);
fileItem.appendChild(fileActions);
fileList.appendChild(fileItem);
});
}
// Get file icon based on type
function getFileIcon(fileType) {
if (fileType.includes('pdf')) return 'fas fa-file-pdf';
if (fileType.includes('word') || fileType.includes('document')) return 'fas fa-file-word';
if (fileType.includes('image')) return 'fas fa-file-image';
return 'fas fa-file';
}
// Format file size
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}
// Update progress bar
function updateProgress() {
const textFilled = document.getElementById('answer').value.length > 200;
const filesUploaded = files.length > 0;
const termsChecked = document.getElementById('terms').checked;
let progress = 0;
if (textFilled) progress += 40;
if (filesUploaded) progress += 40;
if (termsChecked) progress += 20;
progressBar.style.width = progress + '%';
progressText.textContent = progress + '%';
// Change color based on progress
if (progress < 40) progressBar.className = 'bg-red-500 h-2.5 rounded-full progress-bar';
else if (progress < 80) progressBar.className = 'bg-yellow-500 h-2.5 rounded-full progress-bar';
else progressBar.className = 'bg-green-500 h-2.5 rounded-full progress-bar';
}
// Form submission
form.addEventListener('submit', function(e) {
e.preventDefault();
// Simulate submission
progressBar.className = 'bg-blue-600 h-2.5 rounded-full progress-bar';
progressBar.style.width = '100%';
progressText.textContent = '100%';
// Show success modal
setTimeout(() => {
successModal.classList.remove('hidden');
}, 1000);
});
// Initialize
updateFileList();
updateProgress();
});
function closeModal() {
document.getElementById('success-modal').classList.add('hidden');
}
</script>
Step 5: Add a Success Modal
When the form is submitted, we show a confirmation modal.
Modal HTML
<!-- Success Modal -->
<div id="success-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
<div class="bg-white rounded-xl p-6 max-w-sm w-full mx-4">
<div class="text-center">
<div class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100 mb-4">
<i class="fas fa-check text-green-600 text-xl"></i>
</div>
<h3 class="text-lg font-medium text-gray-900 mb-2">Submission Successful!</h3>
<p class="text-sm text-gray-500 mb-6">Your assignment has been submitted successfully.</p>
<button onclick="closeModal()" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg transition">
Close
</button>
</div>
</div>
</div>