HTML & JS Topic
HTML Advanced Forms
1. Form Validation
Built-in HTML5 Validation
html
<form id="signup-form" novalidate>
<!-- Required field -->
<input type="text" required>
<!-- Pattern validation (regex) -->
<input type="text" pattern="[A-Za-z]{3,}"
title="Minimum 3 letters, no numbers">
<!-- Email validation -->
<input type="email" required>
<!-- URL validation -->
<input type="url">
<!-- Number range -->
<input type="number" min="18" max="120" step="1">
<!-- Date range -->
<input type="date" min="2024-01-01" max="2024-12-31">
<!-- Character length -->
<input type="text" minlength="2" maxlength="50">
<!-- Custom validation message -->
<input type="text" oninvalid="this.setCustomValidity('Please enter your name')"
oninput="this.setCustomValidity('')">
</form>
JavaScript Validation Example
html
<form id="registration-form" novalidate>
<div class="form-group">
<label for="username">Username *</label>
<input type="text" id="username" name="username">
<div class="error" id="username-error"></div>
</div>
<div class="form-group">
<label for="email">Email *</label>
<input type="email" id="email" name="email">
<div class="error" id="email-error"></div>
</div>
<button type="submit">Register</button>
</form>
<script>
document.getElementById('registration-form').addEventListener('submit', function(e) {
e.preventDefault();
let isValid = true;
// Clear previous errors
document.querySelectorAll('.error').forEach(el => el.textContent = '');
// Username validation
const username = document.getElementById('username').value.trim();
if (username.length < 3) {
document.getElementById('username-error').textContent =
'Username must be at least 3 characters';
isValid = false;
}
// Email validation
const email = document.getElementById('email').value.trim();
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
document.getElementById('email-error').textContent =
'Please enter a valid email address';
isValid = false;
}
// Password validation example
const password = document.getElementById('password').value;
if (password.length < 8) {
// Show error
isValid = false;
}
if (isValid) {
// Form is valid - submit it
this.submit();
}
});
</script>
<style>
.error {
color: #dc3545;
font-size: 0.875em;
margin-top: 0.25rem;
}
input:invalid {
border-color: #dc3545;
}
input:valid {
border-color: #28a745;
}
</style>
Real-time Validation
html
<input type="email" id="email-input"
onblur="validateEmail(this)"
oninput="clearError(this)">
<div class="error" id="email-error"></div>
<script>
function validateEmail(input) {
const errorDiv = document.getElementById('email-error');
const email = input.value.trim();
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!email) {
errorDiv.textContent = 'Email is required';
input.classList.add('invalid');
} else if (!emailRegex.test(email)) {
errorDiv.textContent = 'Please enter a valid email';
input.classList.add('invalid');
} else {
errorDiv.textContent = '';
input.classList.remove('invalid');
input.classList.add('valid');
}
}
function clearError(input) {
input.classList.remove('invalid', 'valid');
const errorId = input.id + '-error';
const errorDiv = document.getElementById(errorId);
if (errorDiv) errorDiv.textContent = '';
}
</script>
2. Advanced Input Attributes
Input Types for Specific Data
html
<!-- Color picker -->
<label>Favorite Color: <input type="color" name="favcolor"></label>
<!-- Date and Time -->
<label>Date: <input type="date" name="birthdate"></label>
<label>Time: <input type="time" name="meeting-time"></label>
<label>Date & Time: <input type="datetime-local" name="event"></label>
<label>Month: <input type="month" name="month"></label>
<label>Week: <input type="week" name="week"></label>
<!-- Range slider -->
<label>Volume:
<input type="range" name="volume" min="0" max="100" value="50" step="10">
<output for="volume">50</output>
</label>
<!-- Search with suggestions -->
<label>Search:
<input type="search" name="q" list="suggestions">
<datalist id="suggestions">
<option value="HTML">
<option value="CSS">
<option value="JavaScript">
<option value="React">
<option value="Vue">
</datalist>
</label>
Advanced Attributes
html
<!-- Auto-focus on page load -->
<input type="text" name="username" autofocus>
<!-- Auto-complete -->
<input type="text" name="name" autocomplete="name">
<input type="email" name="email" autocomplete="email">
<input type="tel" name="phone" autocomplete="tel">
<input type="password" name="password" autocomplete="new-password">
<!-- Placeholder with examples -->
<input type="text" placeholder="Enter your username"
title="Use letters and numbers only">
<!-- Multiple file upload -->
<input type="file" name="files" multiple accept=".jpg,.png,.pdf">
<!-- Readonly and disabled -->
<input type="text" value="Read Only" readonly>
<input type="text" value="Cannot Edit" disabled>
<!-- Spell check -->
<textarea spellcheck="true">This text will be spell checked</textarea>
<textarea spellcheck="false">This text won't be spell checked</textarea>
<!-- Input mode for mobile keyboards -->
<input type="text" inputmode="text" placeholder="Text keyboard">
<input type="text" inputmode="numeric" placeholder="Numeric keyboard">
<input type="text" inputmode="email" placeholder="Email keyboard">
<input type="text" inputmode="tel" placeholder="Telephone keyboard">
<input type="text" inputmode="url" placeholder="URL keyboard">
Pattern Attribute with Regex
html
<!-- Only letters and spaces -->
<input type="text" pattern="[A-Za-z\s]+" title="Letters only">
<!-- US Phone Number -->
<input type="tel" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"
placeholder="123-456-7890" title="Format: 123-456-7890">
<!-- Strong Password (8+ chars, upper, lower, number, special) -->
<input type="password"
pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
title="8+ chars with uppercase, lowercase, number, and special character">
<!-- Credit Card (16 digits) -->
<input type="text" pattern="[0-9]{16}" maxlength="16"
placeholder="1234567812345678">
<!-- ZIP Code (US) -->
<input type="text" pattern="[0-9]{5}" maxlength="5" placeholder="12345">
<!-- Date (YYYY-MM-DD) -->
<input type="text" pattern="\d{4}-\d{2}-\d{2}"
placeholder="YYYY-MM-DD">
3. Select Elements
Basic Select
html
<label for="country">Country:</label>
<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="jp">Japan</option>
</select>
Select with Groups
html
<label for="car">Choose a car:</label>
<select id="car" name="car">
<optgroup label="German Cars">
<option value="bmw">BMW</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</optgroup>
<optgroup label="Japanese Cars">
<option value="toyota">Toyota</option>
<option value="honda">Honda</option>
<option value="nissan">Nissan</option>
</optgroup>
<optgroup label="American Cars" disabled>
<option value="ford">Ford</option>
<option value="chevrolet">Chevrolet</option>
</optgroup>
</select>
Multiple Select
html
<label for="skills">Skills (hold Ctrl/Cmd to select multiple):</label>
<select id="skills" name="skills" multiple size="4">
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="js">JavaScript</option>
<option value="react">React</option>
<option value="node">Node.js</option>
<option value="python">Python</option>
</select>
Dynamic Select with JavaScript
html
<label for="state">State:</label>
<select id="state" name="state">
<!-- Options will be added by JavaScript -->
</select>
<label for="city">City:</label>
<select id="city" name="city" disabled>
<!-- Options will be added based on state selection -->
</select>
<script>
const states = {
us: ['New York', 'California', 'Texas'],
ca: ['Ontario', 'Quebec', 'British Columbia'],
uk: ['England', 'Scotland', 'Wales']
};
const cities = {
'New York': ['New York City', 'Buffalo', 'Rochester'],
'California': ['Los Angeles', 'San Francisco', 'San Diego'],
'Texas': ['Houston', 'Dallas', 'Austin']
};
// Populate states dropdown
const stateSelect = document.getElementById('state');
Object.keys(states).forEach(state => {
const option = document.createElement('option');
option.value = state;
option.textContent = state.toUpperCase();
stateSelect.appendChild(option);
});
// When state changes, populate cities
stateSelect.addEventListener('change', function() {
const citySelect = document.getElementById('city');
citySelect.innerHTML = '<option value="">-- Select a city --</option>';
citySelect.disabled = false;
const selectedState = this.value;
if (selectedState && cities[selectedState]) {
cities[selectedState].forEach(city => {
const option = document.createElement('option');
option.value = city.toLowerCase();
option.textContent = city;
citySelect.appendChild(option);
});
}
});
</script>
4. Textarea Elements
Basic Textarea
html
<label for="message">Message:</label>
<textarea id="message" name="message"
rows="5" cols="50"
placeholder="Enter your message here..."></textarea>
Textarea with Advanced Features
html
<label for="bio">Biography:</label>
<textarea id="bio" name="bio"
rows="6"
cols="60"
minlength="50"
maxlength="500"
wrap="soft" <!-- or "hard" -->
spellcheck="true"
autocapitalize="sentences"
autocomplete="off"
placeholder="Tell us about yourself (50-500 characters)">
</textarea>
<!-- Character counter -->
<div class="char-counter">
<span id="char-count">0</span>/500 characters
</div>
<script>
const textarea = document.getElementById('bio');
const charCount = document.getElementById('char-count');
textarea.addEventListener('input', function() {
const length = this.value.length;
charCount.textContent = length;
if (length > 500) {
this.value = this.value.substring(0, 500);
charCount.textContent = 500;
}
// Visual feedback
charCount.style.color = length > 450 ? '#dc3545' : '#28a745';
});
</script>
Rich Text Preview
html
<div class="editor-container">
<label for="content">Content:</label>
<textarea id="content" name="content"
rows="8"
placeholder="Write your content here..."></textarea>
<div class="preview">
<h4>Preview:</h4>
<div id="preview-content"></div>
</div>
</div>
<script>
const contentArea = document.getElementById('content');
const preview = document.getElementById('preview-content');
contentArea.addEventListener('input', function() {
// Simple markdown-like preview
let html = this.value
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>') // **bold**
.replace(/\*(.*?)\*/g, '<em>$1</em>') // *italic*
.replace(/`(.*?)`/g, '<code>$1</code>') // `code`
.replace(/\n/g, '<br>'); // line breaks
preview.innerHTML = html || '<em>Start typing to see preview...</em>';
});
</script>
5. Fieldset & Legend
Basic Fieldset Structure
html
<form>
<fieldset>
<legend>Personal Information</legend>
<div class="form-group">
<label for="first-name">First Name:</label>
<input type="text" id="first-name" name="first-name" required>
</div>
<div class="form-group">
<label for="last-name">Last Name:</label>
<input type="text" id="last-name" name="last-name" required>
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
</div>
</fieldset>
<fieldset>
<legend>Account Settings</legend>
<div class="form-group">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
</div>
</fieldset>
</form>
<style>
fieldset {
border: 2px solid #007bff;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
background: #f8f9fa;
}
legend {
font-weight: bold;
color: #007bff;
padding: 0 10px;
background: white;
border: 2px solid #007bff;
border-radius: 4px;
}
.form-group {
margin-bottom: 15px;
}
</style>
Nested Fieldsets
html
<form>
<fieldset>
<legend>Shipping Address</legend>
<fieldset>
<legend>Recipient</legend>
<input type="text" name="ship-name" placeholder="Full Name">
<input type="tel" name="ship-phone" placeholder="Phone Number">
</fieldset>
<fieldset>
<legend>Address</legend>
<input type="text" name="ship-address" placeholder="Street Address">
<input type="text" name="ship-city" placeholder="City">
<input type="text" name="ship-zip" placeholder="ZIP Code">
</fieldset>
</fieldset>
</form>
Fieldset with Radio Buttons
html
<fieldset>
<legend>Payment Method</legend>
<div class="radio-group">
<label>
<input type="radio" name="payment" value="credit" checked>
Credit Card
</label>
<label>
<input type="radio" name="payment" value="paypal">
PayPal
</label>
<label>
<input type="radio" name="payment" value="bank">
Bank Transfer
</label>
</div>
<!-- Conditional fields based on selection -->
<div id="credit-card-fields" class="conditional-fields">
<input type="text" name="card-number" placeholder="Card Number">
<input type="text" name="card-expiry" placeholder="MM/YY">
<input type="text" name="card-cvc" placeholder="CVC">
</div>
</fieldset>
<script>
document.querySelectorAll('input[name="payment"]').forEach(radio => {
radio.addEventListener('change', function() {
document.querySelectorAll('.conditional-fields').forEach(field => {
field.style.display = 'none';
});
if (this.value === 'credit') {
document.getElementById('credit-card-fields').style.display = 'block';
}
});
});
</script>
Disabled Fieldset
html
<fieldset disabled>
<legend>Additional Information (Optional)</legend>
<div class="form-group">
<label for="company">Company:</label>
<input type="text" id="company" name="company">
</div>
<div class="form-group">
<label for="website">Website:</label>
<input type="url" id="website" name="website">
</div>
<button type="button" onclick="enableFieldset()">Enable Section</button>
</fieldset>
<script>
function enableFieldset() {
const fieldset = document.querySelector('fieldset[disabled]');
fieldset.disabled = false;
fieldset.style.opacity = '1';
}
</script>
6. Complete Advanced Form Example
html
<!DOCTYPE html>
<html>
<head>
<title>Advanced Registration Form</title>
<style>
* { box-sizing: border-box; }
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
form { background: #f8f9fa; padding: 30px; border-radius: 10px; }
fieldset { border: 2px solid #6c757d; border-radius: 8px; padding: 20px; margin-bottom: 25px; }
legend { background: white; padding: 5px 15px; border: 2px solid #6c757d; border-radius: 5px; font-weight: bold; color: #495057; }
.form-group { margin-bottom: 15px; }
label { display: block; margin-bottom: 5px; font-weight: 600; color: #495057; }
input, select, textarea { width: 100%; padding: 10px; border: 1px solid #ced4da; border-radius: 4px; font-size: 16px; }
input:focus, select:focus, textarea:focus { outline: none; border-color: #80bdff; box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25); }
.radio-group, .checkbox-group { display: flex; flex-wrap: wrap; gap: 15px; margin: 10px 0; }
.radio-group label, .checkbox-group label { display: flex; align-items: center; font-weight: normal; }
input[type="radio"], input[type="checkbox"] { width: auto; margin-right: 8px; }
button { background: #007bff; color: white; border: none; padding: 12px 30px; border-radius: 5px; font-size: 16px; cursor: pointer; }
button:hover { background: #0056b3; }
.error { color: #dc3545; font-size: 14px; margin-top: 5px; display: none; }
.char-counter { text-align: right; font-size: 14px; color: #6c757d; margin-top: 5px; }
.success { color: #28a745; }
.warning { color: #ffc107; }
.danger { color: #dc3545; }
.helper-text { font-size: 12px; color: #6c757d; margin-top: 3px; }
.form-row { display: flex; gap: 15px; }
.form-row .form-group { flex: 1; }
@media (max-width: 600px) { .form-row { flex-direction: column; } }
</style>
</head>
<body>
<h1>Complete Registration Form</h1>
<form id="advanced-form" novalidate>
<!-- Personal Information -->
<fieldset>
<legend><span class="required">*</span> Personal Information</legend>
<div class="form-row">
<div class="form-group">
<label for="first-name">First Name <span class="required">*</span></label>
<input type="text" id="first-name" name="first-name"
required minlength="2" maxlength="50"
pattern="[A-Za-z\s\-']+"
title="Only letters, spaces, hyphens, and apostrophes allowed">
<div class="error" id="first-name-error"></div>
</div>
<div class="form-group">
<label for="last-name">Last Name <span class="required">*</span></label>
<input type="text" id="last-name" name="last-name"
required minlength="2" maxlength="50"
pattern="[A-Za-z\s\-']+">
<div class="error" id="last-name-error"></div>
</div>
</div>
<div class="form-group">
<label for="email">Email Address <span class="required">*</span></label>
<input type="email" id="email" name="email"
required
autocomplete="email"
placeholder="you@example.com">
<div class="error" id="email-error"></div>
</div>
<div class="form-group">
<label for="phone">Phone Number</label>
<input type="tel" id="phone" name="phone"
pattern="[0-9\-\+\s\(\)]{10,}"
placeholder="(123) 456-7890"
title="Format: (123) 456-7890">
<div class="helper-text">Format: (123) 456-7890 or 123-456-7890</div>
</div>
<div class="form-group">
<label for="dob">Date of Birth</label>
<input type="date" id="dob" name="dob"
min="1900-01-01" max="2024-01-01">
</div>
</fieldset>
<!-- Account Information -->
<fieldset>
<legend><span class="required">*</span> Account Information</legend>
<div class="form-group">
<label for="username">Username <span class="required">*</span></label>
<input type="text" id="username" name="username"
required minlength="3" maxlength="30"
pattern="[A-Za-z0-9_\-]+"
title="Letters, numbers, underscores, and hyphens only">
<div class="char-counter">
<span id="username-count">0</span>/30 characters
</div>
<div class="error" id="username-error"></div>
</div>
<div class="form-row">
<div class="form-group">
<label for="password">Password <span class="required">*</span></label>
<input type="password" id="password" name="password"
required minlength="8"
pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$">
<div class="error" id="password-error"></div>
<div class="helper-text">
8+ characters with uppercase, lowercase, and number
</div>
</div>
<div class="form-group">
<label for="confirm-password">Confirm Password <span class="required">*</span></label>
<input type="password" id="confirm-password" name="confirm-password" required>
<div class="error" id="confirm-password-error"></div>
</div>
</div>
</fieldset>
<!-- Preferences -->
<fieldset>
<legend>Preferences</legend>
<div class="form-group">
<label>Communication Preferences</label>
<div class="checkbox-group">
<label>
<input type="checkbox" name="newsletter" value="email" checked>
Email Newsletter
</label>
<label>
<input type="checkbox" name="notifications" value="sms">
SMS Notifications
</label>
<label>
<input type="checkbox" name="promotions" value="promo">
Promotional Offers
</label>
</div>
</div>
<div class="form-group">
<label for="timezone">Timezone</label>
<select id="timezone" name="timezone">
<option value="">-- Select Timezone --</option>
<option value="est">Eastern Time (ET)</option>
<option value="cst">Central Time (CT)</option>
<option value="mst">Mountain Time (MT)</option>
<option value="pst" selected>Pacific Time (PT)</option>
<option value="akst">Alaska Time (AKT)</option>
<option value="hst">Hawaii Time (HT)</option>
</select>
</div>
<div class="form-group">
<label for="bio">Biography</label>
<textarea id="bio" name="bio" rows="4"
maxlength="500"
placeholder="Tell us about yourself (optional)"></textarea>
<div class="char-counter">
<span id="bio-count">0</span>/500 characters
</div>
</div>
</fieldset>
<!-- Terms -->
<fieldset>
<legend><span class="required">*</span> Terms & Conditions</legend>
<div class="form-group">
<label>
<input type="checkbox" id="terms" name="terms" required>
I agree to the <a href="/terms" target="_blank">Terms and Conditions</a>
and <a href="/privacy" target="_blank">Privacy Policy</a>
</label>
<div class="error" id="terms-error"></div>
</div>
</fieldset>
<!-- Submit -->
<div class="form-group">
<button type="submit">Create Account</button>
<button type="reset">Clear Form</button>
</div>
</form>
<script>
document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('advanced-form');
const usernameInput = document.getElementById('username');
const bioInput = document.getElementById('bio');
const passwordInput = document.getElementById('password');
const confirmPasswordInput = document.getElementById('confirm-password');
// Character counters
usernameInput.addEventListener('input', updateCounter);
bioInput.addEventListener('input', updateCounter);
function updateCounter(e) {
const counter = document.getElementById(e.target.id + '-count');
if (counter) {
const length = e.target.value.length;
counter.textContent = length;
// Visual feedback
const max = e.target.maxLength || 30;
if (length > max * 0.9) {
counter.className = 'danger';
} else if (length > max * 0.7) {
counter.className = 'warning';
} else {
counter.className = 'success';
}
}
}
// Password confirmation
confirmPasswordInput.addEventListener('input', function() {
const errorDiv = document.getElementById('confirm-password-error');
if (passwordInput.value !== this.value) {
errorDiv.textContent = 'Passwords do not match';
errorDiv.style.display = 'block';
} else {
errorDiv.style.display = 'none';
}
});
// Form validation
form.addEventListener('submit', function(e) {
e.preventDefault();
let isValid = true;
// Clear all errors
document.querySelectorAll('.error').forEach(el => {
el.textContent = '';
el.style.display = 'none';
});
// Check passwords match
if (passwordInput.value !== confirmPasswordInput.value) {
document.getElementById('confirm-password-error').textContent =
'Passwords do not match';
document.getElementById('confirm-password-error').style.display = 'block';
isValid = false;
}
// Check password strength
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/;
if (!passwordRegex.test(passwordInput.value)) {
document.getElementById('password-error').textContent =
'Password must contain uppercase, lowercase, and number';
document.getElementById('password-error').style.display = 'block';
isValid = false;
}
// Custom email validation
const email = document.getElementById('email').value;
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
document.getElementById('email-error').textContent =
'Please enter a valid email address';
document.getElementById('email-error').style.display = 'block';
isValid = false;
}
if (isValid) {
// Simulate form submission
alert('Form submitted successfully!');
// form.submit(); // Uncomment for actual submission
}
});
// Real-time validation
form.querySelectorAll('input, select, textarea').forEach(input => {
input.addEventListener('blur', function() {
if (!this.checkValidity()) {
const errorId = this.id + '-error';
const errorDiv = document.getElementById(errorId);
if (errorDiv) {
errorDiv.textContent = this.validationMessage;
errorDiv.style.display = 'block';
}
}
});
input.addEventListener('input', function() {
const errorId = this.id + '-error';
const errorDiv = document.getElementById(errorId);
if (errorDiv) {
errorDiv.style.display = 'none';
}
});
});
});
</script>
</body>
</html>
Key Points to Remember
-
Always use
labelelements withforattributes for accessibility -
HTML5 validation is good for basic checks but always validate server-side
-
Use appropriate input types for better mobile UX and validation
-
Group related fields with
<fieldset>and<legend> -
Provide helpful error messages that tell users how to fix problems
-
Use
autocompleteto help users fill forms faster -
Consider character limits and provide counters for text inputs
-
Test forms thoroughly on different devices and browsers
Advanced forms with proper validation, grouping, and user-friendly features significantly improve the user experience and reduce form abandonment rates.
Comments (0)
No comments yet. Be the first to comment!