Lesson 17: HTML Forms Part 3
Master file uploads, hidden fields, form security, and advanced form styling techniques
Start LearningFile Uploads
The <input type="file"> element allows users to select one or more files from their device storage to upload to a server.
enctype attribute to multipart/form-data and the method to POST.
Basic File Upload
<form action="/upload" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="avatar">Upload Profile Picture:</label>
<input type="file" id="avatar" name="avatar" accept="image/*">
</div>
<button type="submit">Upload</button>
</form>
Result:
Multiple File Upload
Add the multiple attribute to allow selecting multiple files:
<form action="/upload" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="photos">Upload Photos:</label>
<input type="file" id="photos" name="photos" accept="image/*" multiple>
</div>
<button type="submit">Upload Files</button>
</form>
Result:
File Upload with Drag & Drop
Note: Drag and drop functionality requires JavaScript to handle the events.
<div id="drop-area" class="file-upload-container">
<h4>Drag & Drop Files Here</h4>
<p>or</p>
<input type="file" id="file-input" multiple style="display:none;">
<button class="file-upload-btn" onclick="document.getElementById('file-input').click()">
Select Files
</button>
<div id="file-list" class="file-list"></div>
</div>
<script>
const dropArea = document.getElementById('drop-area');
const fileInput = document.getElementById('file-input');
const fileList = document.getElementById('file-list');
// Prevent default drag behaviors
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
// Highlight drop area when item is dragged over it
['dragenter', 'dragover'].forEach(eventName => {
dropArea.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, unhighlight, false);
});
function highlight() {
dropArea.classList.add('drag-over');
}
function unhighlight() {
dropArea.classList.remove('drag-over');
}
// Handle dropped files
dropArea.addEventListener('drop', handleDrop, false);
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
handleFiles(files);
}
// Handle selected files from input
fileInput.addEventListener('change', function() {
handleFiles(this.files);
});
function handleFiles(files) {
for (let i = 0; i < files.length; i++) {
const file = files[i];
displayFile(file);
}
}
function displayFile(file) {
const fileItem = document.createElement('div');
fileItem.className = 'file-item';
const fileInfo = document.createElement('div');
fileInfo.style.display = 'flex';
fileInfo.style.alignItems = 'center';
fileInfo.style.flex = '1';
const fileIcon = document.createElement('i');
fileIcon.className = 'fas fa-file file-icon';
const fileName = document.createElement('div');
fileName.className = 'file-name';
fileName.textContent = file.name;
const fileSize = document.createElement('div');
fileSize.className = 'file-size';
fileSize.textContent = formatFileSize(file.size);
const removeBtn = document.createElement('button');
removeBtn.className = 'remove-file';
removeBtn.innerHTML = '';
removeBtn.onclick = function() {
fileItem.remove();
};
fileInfo.appendChild(fileIcon);
fileInfo.appendChild(fileName);
fileInfo.appendChild(fileSize);
fileItem.appendChild(fileInfo);
fileItem.appendChild(removeBtn);
fileList.appendChild(fileItem);
}
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(2)) + ' ' + sizes[i];
}
</script>
Result:
Drag & Drop Files Here
or
Hidden Fields
Hidden fields allow you to include data that isn't visible to the user but is submitted with the form.
Basic Hidden Field
<form action="/submit" method="post">
<!-- Visible fields -->
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>
</div>
<!-- Hidden field -->
<input type="hidden" id="user-id" name="user_id" value="12345">
<button type="submit">Submit</button>
</form>
Result:
Hidden fields are not visible to the user but are included in form submission.
Security: CSRF Tokens
Security Alert: Always include CSRF tokens in your forms to prevent Cross-Site Request Forgery attacks.
<form action="/update-profile" method="post">
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
</div>
<!-- CSRF Token -->
<input type="hidden" name="csrf_token" value="a1b2c3d4e5f6g7h8i9j0">
<button type="submit">Update Email</button>
</form>
Result:
CSRF tokens protect against malicious form submissions.
Advanced Form Styling
Create visually appealing forms with custom styling for form controls using CSS.
Custom Checkboxes
<style>
.custom-checkbox {
display: flex;
align-items: center;
margin-bottom: 10px;
cursor: pointer;
}
.custom-checkbox input {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
.checkmark {
height: 20px;
width: 20px;
background-color: #eee;
border: 1px solid #ccc;
border-radius: 4px;
margin-right: 10px;
position: relative;
transition: all 0.2s;
}
.custom-checkbox:hover input ~ .checkmark {
background-color: #ddd;
}
.custom-checkbox input:checked ~ .checkmark {
background-color: var(--primary);
border-color: var(--primary-dark);
}
.checkmark:after {
content: "";
position: absolute;
display: none;
left: 6px;
top: 2px;
width: 5px;
height: 10px;
border: solid white;
border-width: 0 3px 3px 0;
transform: rotate(45deg);
}
.custom-checkbox input:checked ~ .checkmark:after {
display: block;
}
</style>
<div class="form-group">
<label>Notification Preferences:</label>
<label class="custom-checkbox">
<input type="checkbox" name="email_notifications" checked>
<span class="checkmark"></span>
Email Notifications
</label>
<label class="custom-checkbox">
<input type="checkbox" name="push_notifications">
<span class="checkmark"></span>
Push Notifications
</label>
<label class="custom-checkbox">
<input type="checkbox" name="sms_notifications">
<span class="checkmark"></span>
SMS Notifications
</label>
</div>
Result:
Custom Radio Buttons
<style>
.custom-radio {
display: flex;
align-items: center;
margin-bottom: 10px;
cursor: pointer;
}
.custom-radio input {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
.radiomark {
height: 20px;
width: 20px;
background-color: #eee;
border: 1px solid #ccc;
border-radius: 50%;
margin-right: 10px;
position: relative;
transition: all 0.2s;
}
.custom-radio:hover input ~ .radiomark {
background-color: #ddd;
}
.custom-radio input:checked ~ .radiomark {
background-color: var(--primary);
border-color: var(--primary-dark);
}
.radiomark:after {
content: "";
position: absolute;
display: none;
top: 5px;
left: 5px;
width: 8px;
height: 8px;
border-radius: 50%;
background: white;
}
.custom-radio input:checked ~ .radiomark:after {
display: block;
}
</style>
<div class="form-group">
<label>Preferred Contact Method:</label>
<label class="custom-radio">
<input type="radio" name="contact" value="email" checked>
<span class="radiomark"></span>
Email
</label>
<label class="custom-radio">
<input type="radio" name="contact" value="phone">
<span class="radiomark"></span>
Phone
</label>
<label class="custom-radio">
<input type="radio" name="contact" value="mail">
<span class="radiomark"></span>
Postal Mail
</label>
</div>
Result:
Custom Select Dropdown
<style>
.custom-select {
position: relative;
margin-bottom: 15px;
}
.custom-select select {
appearance: none;
background-color: white;
padding: 10px 40px 10px 15px;
width: 100%;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
}
.custom-select::after {
content: "";
position: absolute;
top: 50%;
right: 15px;
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 6px solid var(--primary);
transform: translateY(-50%);
pointer-events: none;
}
</style>
<div class="form-group">
<label for="country">Country:</label>
<div class="custom-select">
<select id="country" name="country">
<option value="">Select a country</option>
<option value="us">United States</option>
<option value="ca">Canada</option>
<option value="uk">United Kingdom</option>
<option value="au">Australia</option>
<option value="de">Germany</option>
<option value="fr">France</option>
<option value="jp">Japan</option>
</select>
</div>
</div>
Result:
Working with Form Data
JavaScript provides the FormData API for easily working with form data, especially when submitting forms via AJAX.
FormData API Example
<form id="user-form">
<div class="form-group">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
</div>
<div class="form-group">
<label for="user-email">Email:</label>
<input type="email" id="user-email" name="email" required>
</div>
<div class="form-group">
<label for="user-avatar">Avatar:</label>
<input type="file" id="user-avatar" name="avatar" accept="image/*">
</div>
<div class="form-actions">
<button type="submit">Submit</button>
</div>
</form>
<div id="form-data-output" style="margin-top: 20px; padding: 15px; background: #f9f9f9; border-radius: 8px;">
<h4>Form Data Output:</h4>
<pre id="output"></pre>
</div>
<script>
document.getElementById('user-form').addEventListener('submit', function(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
// Display form data
let output = '';
for (let [key, value] of formData.entries()) {
output += `${key}: ${value}\n`;
}
document.getElementById('output').textContent = output;
// In a real application, you would send the data to a server
// Example using fetch:
/*
fetch('/submit', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch(error => {
console.error('Error:', error);
});
*/
});
</script>
Result:
Form Data Output:
Practical Exercise: File Upload Form
Create a file upload form with the following features:
Your Task:
Create a document upload form with:
- Personal information fields (name, email)
- Document type selection (dropdown)
- File upload with drag & drop support
- Custom styled checkboxes for consent
- CSRF token for security
- Form validation
- AJAX submission using FormData