Session 2
HTML Forms
HTML Forms are a fundamental building block of interactive web development, designed to collect user input dynamically at runtime. In this session, you will gain a foundational understanding of how to create, structure, and implement HTML forms to gather information from users. The data entered through these forms is typically transmitted to a web server for processing, validation, and storage.
Forms are widely used to collect essential information such as usernames, passwords, contact details (e-mail IDs, mobile numbers), and other user preferences. This session introduces the core <form> container element and explores the various input controls it can hold, including:
- Text fields & text areas
- Radio buttons & checkboxes
- Submit & clickable buttons
- Labels for accessibility and clarity
- HTML5-specific input types (e.g., email, search, url, date, month, time)
Suggestion
Also, Lab manual includes great examples before exercises, make sure to go through them as well.
Objective
After Completing this session, one should be able to:
- Understand the HTML form element
- use the form element in HTML
- use HTML to acquire user input and process it
- Create forms with basic elements like textboxes, checkboxes, radio buttons and submit buttons.
- Create forms using HTML5 elements like E-Mail address field and form validation
Question 1
Problem Statement
Create an HTML webpage, as shown in the figure [2.1]. The user can specify any expression as input. Use form element to collect the user data.
Figure 2.1 (Demo)
- Reference by question
- Working demo for preview
Expression
Result
Code
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vanilla Expression Calculator</title>
<style>
.demo-1 {
color: black;
}
/* Replicates: grid grid-cols-2 border p-1 w-1/3 mt-3 gap-1 */
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr;
border: 1px solid #333;
color: black;
padding: 0.25rem;
width: 33.333%;
margin-top: 0.75rem;
gap: 0.25rem;
box-sizing: border-box;
font-family:
system-ui,
-apple-system,
sans-serif;
}
/* Replicates: border p-1 px-2 font-bold */
.grid-item,
.grid-input {
border: 1px solid #333;
padding: 0.25rem 0.5rem;
font-weight: bold;
box-sizing: border-box;
margin: 0;
color: black;
}
.grid-input {
outline: none;
background: #fff;
}
.grid-input:focus {
border-color: #2563eb;
box-shadow: 0 0 0 1px #2563eb;
}
.grid-header {
background-color: #f3f4f6;
}
</style>
</head>
<body class="demo-1">
<div class="grid-container">
<p class="grid-item grid-header">Expression</p>
<p class="grid-item grid-header">Result</p>
<input type="text" class="grid-input" id="expression-1" />
<input type="text" class="grid-input" id="result-1" readonly />
<input type="text" class="grid-input" id="expression-2" />
<input type="text" class="grid-input" id="result-2" readonly />
</div>
<script>
// 1. Mirror the $state object
const inputvalue = {
1: "1+1",
2: "1+1*2",
result1: "2",
result2: "3",
};
// 2. Cache DOM elements for performance
const els = {
expr1: document.getElementById("expression-1"),
res1: document.getElementById("result-1"),
expr2: document.getElementById("expression-2"),
res2: document.getElementById("result-2"),
};
// 3. Initialize inputs with default state
els.expr1.value = inputvalue[1];
els.res1.value = inputvalue.result1;
els.expr2.value = inputvalue[2];
els.res2.value = inputvalue.result2;
// 4. Core calculation function
function onInputChange(index) {
const exprEl = index === 1 ? els.expr1 : els.expr2;
const resEl = index === 1 ? els.res1 : els.res2;
// Sync DOM -> State
inputvalue[index] = exprEl.value;
try {
// Note: eval() is used as requested. In production, consider a math parser
// like math.js or new Function() for better security & performance.
const result = eval(inputvalue[index]);
// Sync State -> DOM
inputvalue[`result${index}`] = result;
resEl.value = result;
} catch (error) {
inputvalue[`result${index}`] = "Error";
resEl.value = "Error";
}
}
// 5. Attach event listeners
// Using 'input' fires on every keystroke (better UX for calculators).
// Change to 'change' if you only want it to fire on blur/enter.
els.expr1.addEventListener("input", () => onInputChange(1));
els.expr2.addEventListener("input", () => onInputChange(2));
</script>
</body>
</html>
Question 2
Problem Statement
Create a scrolling list that shows five items from the following list of PC processors: Intel i7, Motorola 68000, AMD Athlon , Intel 8088, AMD Ryzon, Intel Pentium MMX, Intel i3, Intel Pentium II, Intel Pentium III, Intel i5, Intel Celeron, PowerPC G3, PowerPC G4.
Preview
- 1 Intel i7
- 2 Motorola 68000
- 3 AMD Athlon
- 4 Intel 8088
- 5 AMD Ryzen
- 6 Intel Pentium MMX
- 7 Intel i3
- 8 Intel Pentium II
- 9 Intel Pentium III
- 10 Intel i5
- 11 Intel Celeron
- 12 PowerPC G3
- 13 PowerPC G4
Code
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PC Processors Scroll List</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family:
system-ui,
-apple-system,
sans-serif;
background: #0f172a;
display: flex;
justify-content: center;
align-items: center;
height: 100svh;
padding: 12px;
}
.scroll-container {
width: 100%;
max-width: 420px;
height: 50svh;
background: #ffffff;
border-radius: 16px;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
overflow-y: auto;
scroll-behavior: smooth;
position: relative;
}
.list-header {
position: sticky;
top: 0;
background: #1e293b;
color: #f8fafc;
padding: 18px;
text-align: center;
font-size: 1.15rem;
font-weight: 600;
z-index: 10;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
letter-spacing: 0.5px;
}
.processor-list {
list-style: none;
}
.processor-item {
padding: 16px 20px;
border-bottom: 1px solid #e2e8f0;
display: flex;
align-items: center;
gap: 12px;
transition: background 0.2s ease;
}
.processor-item:last-child {
border-bottom: none;
}
.processor-item:hover {
background: #f1f5f9;
}
.item-number {
width: 32px;
height: 32px;
background: linear-gradient(135deg, #3b82f6, #8b5cf6);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 0.75rem;
font-weight: 700;
flex-shrink: 0;
}
.item-name {
font-size: 1rem;
color: #0f172a;
font-weight: 500;
}
/* Custom Scrollbar */
.scroll-container::-webkit-scrollbar {
width: 8px;
}
.scroll-container::-webkit-scrollbar-track {
background: #f8fafc;
}
.scroll-container::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 4px;
border: 2px solid #f8fafc;
}
.scroll-container::-webkit-scrollbar-thumb:hover {
background: #94a3b8;
}
</style>
</head>
<body>
<div class="scroll-container">
<div class="list-header">PC Processors</div>
<ul class="processor-list" id="processorList"></ul>
</div>
<script>
const processors = [
"Intel i7",
"Motorola 68000",
"AMD Athlon",
"Intel 8088",
"AMD Ryzen",
"Intel Pentium MMX",
"Intel i3",
"Intel Pentium II",
"Intel Pentium III",
"Intel i5",
"Intel Celeron",
"PowerPC G3",
"PowerPC G4",
];
const listEl = document.getElementById("processorList");
// Generate list items dynamically
processors.forEach((proc, index) => {
const li = document.createElement("li");
li.className = "processor-item";
li.innerHTML = `
<div class="item-number">${index + 1}</div>
<div class="item-name">${proc}</div>
`;
listEl.appendChild(li);
});
</script>
</body>
</html>
Question 3
Problem Statement
Design a webpage for a software company to accept on-line job applications. The webpage must be designed to use form with elements:
- Position applied for (autofocus), name, nationality, date of birth (selected from an auto picker), address (in a text area), telephone number and email (required).
- Educational history and qualifications.
- Work experience/employment/training in terms of employer history and number of years of experience selected from a slider. Set maximum years of experience to 10 years.
- Personal statement.
- Two referees including names, occupation, relationship, address, telephone.
Preview
Ethercorps
Online Job Application Portal
Code
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Apply Now - TechNova Solutions</title>
<style>
:root {
--primary: #2563eb;
--primary-hover: #1d4ed8;
--bg: #f8fafc;
--surface: #ffffff;
--text: #0f172a;
--text-muted: #475569;
--border: #cbd5e1;
--focus-ring: rgba(37, 99, 235, 0.3);
--error: #ef4444;
--success: #10b981;
--radius: 10px;
--shadow:
0 4px 6px -1px rgb(0 0 0 / 0.1),
0 2px 4px -2px rgb(0 0 0 / 0.1);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family:
system-ui,
-apple-system,
"Segoe UI",
Roboto,
sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.5;
padding: 2rem 1rem;
min-height: 100vh;
}
.container {
max-width: 900px;
margin: 0 auto;
background: var(--surface);
padding: 2.5rem;
border-radius: var(--radius);
box-shadow: var(--shadow);
}
header {
text-align: center;
margin-bottom: 2rem;
padding-bottom: 1.5rem;
border-bottom: 1px solid var(--border);
}
header h1 {
font-size: 1.75rem;
font-weight: 700;
color: var(--text);
}
header p {
color: var(--text-muted);
margin-top: 0.25rem;
}
form {
display: flex;
flex-direction: column;
gap: 1.75rem;
}
fieldset {
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1.5rem;
background: #fdfdfd;
}
legend {
font-weight: 600;
padding: 0 0.5rem;
color: var(--primary);
font-size: 1.1rem;
}
.form-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.25rem;
}
.form-group {
display: flex;
flex-direction: column;
gap: 0.4rem;
}
.form-group.full-width {
grid-column: 1 / -1;
}
label {
font-size: 0.9rem;
font-weight: 500;
color: var(--text);
}
label .req {
color: var(--error);
margin-left: 2px;
}
input,
textarea,
select {
padding: 0.75rem;
border: 1px solid var(--border);
border-radius: 8px;
font-size: 0.95rem;
font-family: inherit;
transition:
border-color 0.2s,
box-shadow 0.2s;
background: #fff;
}
input:focus,
textarea:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px var(--focus-ring);
}
input:invalid:not(:placeholder-shown) {
border-color: var(--error);
}
textarea {
resize: vertical;
min-height: 100px;
}
/* Slider Styling */
.slider-wrapper {
display: flex;
align-items: center;
gap: 1rem;
margin-top: 0.5rem;
}
input[type="range"] {
flex: 1;
cursor: pointer;
accent-color: var(--primary);
}
.slider-value {
min-width: 3ch;
text-align: center;
font-weight: 600;
background: var(--bg);
padding: 0.3rem 0.6rem;
border-radius: 6px;
border: 1px solid var(--border);
}
/* Referees Grid */
.referees-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
}
.referee-card {
background: #fff;
border: 1px solid var(--border);
border-radius: 8px;
padding: 1.25rem;
}
.referee-card h3 {
margin-bottom: 1rem;
font-size: 1rem;
color: var(--text-muted);
border-bottom: 1px dashed var(--border);
padding-bottom: 0.5rem;
}
/* Submit Button */
button[type="submit"] {
background: var(--primary);
color: white;
border: none;
padding: 1rem 2rem;
font-size: 1rem;
font-weight: 600;
border-radius: 8px;
cursor: pointer;
transition:
background 0.2s,
transform 0.1s;
margin-top: 1rem;
align-self: flex-start;
}
button[type="submit"]:hover {
background: var(--primary-hover);
}
button[type="submit"]:active {
transform: scale(0.98);
}
button[type="submit"]:disabled {
background: var(--text-muted);
cursor: not-allowed;
opacity: 0.7;
}
/* Message Toast */
.message {
padding: 1rem;
border-radius: 8px;
margin-top: 1rem;
display: none;
font-weight: 500;
text-align: center;
}
.message.success {
background: #dcfce7;
color: #166534;
border: 1px solid #bbf7d0;
display: block;
}
.message.error {
background: #fee2e2;
color: #991b1b;
border: 1px solid #fecaca;
display: block;
}
@media (max-width: 768px) {
.container {
padding: 1.5rem;
}
.referees-grid {
grid-template-columns: 1fr;
}
button[type="submit"] {
width: 100%;
align-self: center;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>Ethercorps Solutions</h1>
<p>Online Job Application Portal</p>
</header>
<form id="applicationForm" novalidate>
<!-- Personal & Contact -->
<fieldset>
<legend>Personal & Contact Information</legend>
<div class="form-grid">
<div class="form-group full-width">
<label for="position"
>Position Applied For
<span class="req">*</span></label
>
<input
type="text"
id="position"
name="position"
placeholder="e.g. Senior Frontend Developer"
required
autofocus
/>
</div>
<div class="form-group">
<label for="fullName"
>Full Name <span class="req">*</span></label
>
<input
type="text"
id="fullName"
name="fullName"
required
/>
</div>
<div class="form-group">
<label for="nationality"
>Nationality <span class="req">*</span></label
>
<input
type="text"
id="nationality"
name="nationality"
required
/>
</div>
<div class="form-group">
<label for="dob"
>Date of Birth <span class="req">*</span></label
>
<input type="date" id="dob" name="dob" required />
</div>
<div class="form-group">
<label for="email"
>Email Address <span class="req">*</span></label
>
<input
type="email"
id="email"
name="email"
placeholder="[email protected]"
required
/>
</div>
<div class="form-group full-width">
<label for="address">Address</label>
<textarea
id="address"
name="address"
rows="2"
required
></textarea>
</div>
<div class="form-group">
<label for="phone"
>Telephone Number
<span class="req">*</span></label
>
<input
type="tel"
id="phone"
name="phone"
placeholder="+1 (555) 000-0000"
required
/>
</div>
</div>
</fieldset>
<!-- Education -->
<fieldset>
<legend>Education & Qualifications</legend>
<div class="form-group">
<label for="education"
>Educational History & Qualifications</label
>
<textarea
id="education"
name="education"
placeholder="Degrees, certifications, institutions, graduation dates..."
></textarea>
</div>
</fieldset>
<!-- Work Experience -->
<fieldset>
<legend>Work Experience & Training</legend>
<div class="form-group">
<label for="employmentHistory"
>Employer History & Training</label
>
<textarea
id="employmentHistory"
name="employmentHistory"
rows="4"
placeholder="Previous companies, roles, key responsibilities, training programs..."
></textarea>
</div>
<div class="form-group">
<label for="yearsExp"
>Years of Experience (Max 10)</label
>
<div class="slider-wrapper">
<input
type="range"
id="yearsExp"
name="yearsExp"
min="0"
max="10"
step="1"
value="0"
/>
<output id="yearsExpOutput" class="slider-value"
>0</output
>
</div>
</div>
</fieldset>
<!-- Personal Statement -->
<fieldset>
<legend>Personal Statement</legend>
<div class="form-group">
<label for="personalStatement"
>Why are you a strong candidate?
<span class="req">*</span></label
>
<textarea
id="personalStatement"
name="personalStatement"
rows="4"
placeholder="Highlight your skills, motivation, and career objectives..."
required
></textarea>
</div>
</fieldset>
<!-- Referees -->
<fieldset>
<legend>Referees</legend>
<div class="referees-grid">
<div class="referee-card">
<h3>Referee 1</h3>
<div class="form-group">
<label for="ref1Name">Full Name</label>
<input
type="text"
id="ref1Name"
name="ref1Name"
required
/>
</div>
<div class="form-group">
<label for="ref1Occupation">Occupation</label>
<input
type="text"
id="ref1Occupation"
name="ref1Occupation"
required
/>
</div>
<div class="form-group">
<label for="ref1Relationship"
>Relationship</label
>
<input
type="text"
id="ref1Relationship"
name="ref1Relationship"
placeholder="e.g. Former Manager"
required
/>
</div>
<div class="form-group">
<label for="ref1Address">Address</label>
<textarea
id="ref1Address"
name="ref1Address"
rows="2"
required
></textarea>
</div>
<div class="form-group">
<label for="ref1Phone">Telephone</label>
<input
type="tel"
id="ref1Phone"
name="ref1Phone"
required
/>
</div>
</div>
<div class="referee-card">
<h3>Referee 2</h3>
<div class="form-group">
<label for="ref2Name">Full Name</label>
<input
type="text"
id="ref2Name"
name="ref2Name"
required
/>
</div>
<div class="form-group">
<label for="ref2Occupation">Occupation</label>
<input
type="text"
id="ref2Occupation"
name="ref2Occupation"
required
/>
</div>
<div class="form-group">
<label for="ref2Relationship"
>Relationship</label
>
<input
type="text"
id="ref2Relationship"
name="ref2Relationship"
required
/>
</div>
<div class="form-group">
<label for="ref2Address">Address</label>
<textarea
id="ref2Address"
name="ref2Address"
rows="2"
required
></textarea>
</div>
<div class="form-group">
<label for="ref2Phone">Telephone</label>
<input
type="tel"
id="ref2Phone"
name="ref2Phone"
required
/>
</div>
</div>
</div>
</fieldset>
<button type="submit" id="submitBtn">Submit Application</button>
<div id="formMessage" class="message" aria-live="polite"></div>
</form>
</div>
<script>
document.addEventListener("DOMContentLoaded", () => {
const form = document.getElementById("applicationForm");
const slider = document.getElementById("yearsExp");
const sliderOutput = document.getElementById("yearsExpOutput");
const submitBtn = document.getElementById("submitBtn");
const messageDiv = document.getElementById("formMessage");
// Update slider output dynamically
slider.addEventListener("input", () => {
sliderOutput.textContent = slider.value;
});
// Handle form submission
form.addEventListener("submit", (e) => {
e.preventDefault();
messageDiv.className = "message"; // Reset classes
messageDiv.style.display = "none";
// Trigger native HTML5 validation
if (!form.checkValidity()) {
form.reportValidity();
return;
}
// Simulate async submission
submitBtn.disabled = true;
submitBtn.textContent = "Submitting...";
// Collect form data (for demonstration)
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
console.log("Application Data:", data);
// Mock API delay
setTimeout(() => {
messageDiv.textContent =
"✅ Application submitted successfully! We will review your details and contact you shortly.";
messageDiv.classList.add("success");
messageDiv.style.display = "block";
// Reset form
form.reset();
sliderOutput.textContent = "0";
submitBtn.disabled = false;
submitBtn.textContent = "Submit Application";
// Scroll to message
messageDiv.scrollIntoView({
behavior: "smooth",
block: "nearest",
});
}, 1500);
});
});
</script>
</body>
</html>