Skip to content

Commit f826e0d

Browse files
Add files via upload
1 parent b63e5be commit f826e0d

File tree

3 files changed

+312
-0
lines changed

3 files changed

+312
-0
lines changed

css/style.css

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
body {
2+
background: linear-gradient(90deg, #2563eb 60%, #1e40af 100%);
3+
min-height: 100vh;
4+
font-family: 'Segoe UI';
5+
margin: 0;
6+
padding: 0;
7+
}
8+
9+
10+
.form-container {
11+
background: #fff;
12+
width: 500px;
13+
/* center without margin */
14+
position: absolute;
15+
top: 50%;
16+
left: 50%;
17+
transform: translate(-50%, -50%);
18+
/* margin: 50px auto; */
19+
padding: 28px;
20+
border-radius: 12px;
21+
border: 2px solid #000000;
22+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
23+
}
24+
25+
h2 {
26+
text-align: center;
27+
color: #1a365d;
28+
margin-bottom: 18px;
29+
}
30+
31+
.form-group {
32+
margin-bottom: 16px;
33+
display: flex;
34+
flex-direction: column;
35+
}
36+
37+
label {
38+
margin-bottom: 6px;
39+
color: #2d3a4a;
40+
font-weight: 500;
41+
}
42+
43+
input[type="text"],
44+
input[type="email"],
45+
input[type="password"],
46+
input[type="number"],
47+
select {
48+
padding: 10px 12px;
49+
border: 1.5px solid #bfc9d9;
50+
border-radius: 6px;
51+
font-size: 16px;
52+
background: #f9fbfd;
53+
outline: none;
54+
/* outline: none; used to remove the default focus outline */
55+
}
56+
57+
input.valid,
58+
select.valid {
59+
border-color: #10b981;
60+
background: #f0fdf4;
61+
}
62+
63+
input.invalid,
64+
select.invalid {
65+
border-color: #ef4444;
66+
background: #fef2f2;
67+
}
68+
69+
/* Focused field highlight for JS-based focus highlighting */
70+
input.focused,
71+
select.focused {
72+
background: #c1dcff;
73+
box-shadow: 0 0 0 2px #15ff00;
74+
}
75+
76+
button[type="submit"] {
77+
width: 100%;
78+
padding: 12px;
79+
background: linear-gradient(90deg, #2563eb 60%, #1e40af 100%);
80+
color: #fff;
81+
border: none;
82+
border-radius: 6px;
83+
font-size: 1.1rem;
84+
font-weight: 600;
85+
cursor: pointer;
86+
margin-top: 8px;
87+
}
88+
89+
button[type="submit"]:hover {
90+
background: linear-gradient(90deg, #1e40af 60%, #2563eb 100%);
91+
}
92+
93+
/* for the checkBox */
94+
.form-group.terms {
95+
/* Set flex-direction to row so the checkbox and its label appear side by side horizontally instead of stacked vertically */
96+
flex-direction: row;
97+
align-items: center;
98+
margin-bottom: 10px;
99+
}

index.html

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>Job Application Form</title>
8+
<link rel="stylesheet" href="css/style.css">
9+
</head>
10+
11+
<body>
12+
<div class="form-container">
13+
<form id="jobAppForm" novalidate>
14+
<h2>╰(..:: Job Application ::..)╯</h2>
15+
<!-- for the Name input -->
16+
<div class="form-group">
17+
<label for="name">Name</label>
18+
<input type="text" id="name" name="name" required>
19+
</div>
20+
<!-- for the Email input -->
21+
<div class="form-group">
22+
<label for="email">Email</label>
23+
<input type="email" id="email" name="email" required>
24+
</div>
25+
<!-- for the Phone input -->
26+
<div class="form-group">
27+
<label for="phone">Phone</label>
28+
<input type="text" id="phone" name="phone" required maxlength="11">
29+
</div>
30+
<!-- for the Password input -->
31+
<div class="form-group">
32+
<label for="password">Password</label>
33+
<input type="password" id="password" name="password" required>
34+
</div>
35+
<!-- for the Experience Level selection -->
36+
<div class="form-group">
37+
<label for="experience">Experience Level</label>
38+
<select id="experience" name="experience" required style="margin-top:10px;">
39+
<option value="">Select Experience Level</option>
40+
<option value="Entry">Entry Level (0-2 years)</option>
41+
<option value="Mid">Mid Level (3-5 years)</option>
42+
<option value="Senior">Senior Level (6-10 years)</option>
43+
<option value="Executive">Executive (10+ years)</option>
44+
</select>
45+
</div>
46+
<!-- for the Expected Salary input -->
47+
<div class="form-group">
48+
<label for="salary">Expected Salary</label>
49+
<input type="number" id="salary" name="salary" required min="1">
50+
</div>
51+
<!-- for the Terms & conditions checkbox -->
52+
<div class="form-group terms">
53+
<input type="checkbox" id="terms" name="terms" required>
54+
<label for="terms">I agree to the terms & conditions</label>
55+
</div>
56+
<button type="submit">Apply</button>
57+
</form>
58+
</div>
59+
<script src="js/valid.js"></script>
60+
</body>
61+
62+
</html>

js/valid.js

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Job Application Form Validation and UI Feedback
2+
document.addEventListener("DOMContentLoaded", function () {
3+
const form = document.getElementById("jobAppForm");
4+
const name = document.getElementById("name");
5+
const email = document.getElementById("email");
6+
const phone = document.getElementById("phone");
7+
const password = document.getElementById("password");
8+
const experience = document.getElementById("experience");
9+
const salary = document.getElementById("salary");
10+
const terms = document.getElementById("terms");
11+
const fields = [name, email, phone, password, experience, salary];
12+
13+
// Focus highlighting
14+
fields.forEach((field) => {
15+
field.addEventListener("focus", function () {
16+
field.classList.add("focused");
17+
});
18+
field.addEventListener("blur", function () {
19+
// blur event is triggered when the field loses focus
20+
field.classList.remove("focused");
21+
});
22+
});
23+
24+
// Real-time validation feedback
25+
name.addEventListener("input", function () {
26+
validateName();
27+
});
28+
email.addEventListener("input", function () {
29+
validateEmail();
30+
});
31+
phone.addEventListener("input", function () {
32+
validatePhone();
33+
});
34+
password.addEventListener("input", function () {
35+
validatePassword();
36+
});
37+
experience.addEventListener("change", function () {
38+
validateExperience();
39+
});
40+
salary.addEventListener("input", function () {
41+
validateSalary();
42+
});
43+
44+
// Validation functions
45+
/// name input validation
46+
function validateName() {
47+
const val = name.value.trim();
48+
if (/^[A-Za-z ]{3,}$/.test(val)) {
49+
// .test(val) used to check if the value matches the regex pattern
50+
setValid(name);
51+
// setValid() is used to apply the valid class
52+
return true;
53+
} else {
54+
setInvalid(name);
55+
// setInvalid() is used to apply the invalid class
56+
return false;
57+
}
58+
}
59+
60+
/// email input validation
61+
function validateEmail() {
62+
const val = email.value.trim();
63+
if (/^[\w.-]+@[\w-]+\.[A-Za-z]{2,}$/.test(val)) {
64+
setValid(email);
65+
return true;
66+
} else {
67+
setInvalid(email);
68+
return false;
69+
}
70+
}
71+
72+
/// phone input validation
73+
function validatePhone() {
74+
const val = phone.value.trim();
75+
if (/^\d{11}$/.test(val)) {
76+
setValid(phone);
77+
return true;
78+
} else {
79+
setInvalid(phone);
80+
return false;
81+
}
82+
}
83+
84+
/// password input validation
85+
function validatePassword() {
86+
const val = password.value;
87+
if (/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/.test(val)) {
88+
setValid(password);
89+
return true;
90+
} else {
91+
setInvalid(password);
92+
return false;
93+
}
94+
}
95+
96+
/// experience input validation
97+
function validateExperience() {
98+
if (experience.value !== "") {
99+
setValid(experience);
100+
return true;
101+
} else {
102+
setInvalid(experience);
103+
return false;
104+
}
105+
}
106+
107+
/// salary input validation
108+
function validateSalary() {
109+
const val = parseFloat(salary.value);
110+
if (!isNaN(val) && val > 0) {
111+
setValid(salary);
112+
return true;
113+
} else {
114+
setInvalid(salary);
115+
return false;
116+
}
117+
}
118+
119+
// HelperFunctions to set valid/invalid classes
120+
function setValid(field) {
121+
field.classList.remove("invalid");
122+
field.classList.add("valid");
123+
}
124+
function setInvalid(field) {
125+
field.classList.remove("valid");
126+
field.classList.add("invalid");
127+
}
128+
129+
// Form submit validation
130+
form.addEventListener("submit", function (e) {
131+
let errors = [];
132+
if (!validateName())
133+
errors.push("Name must be at least 3 letters (letters only).");
134+
if (!validateEmail()) errors.push("Enter a valid email address.");
135+
if (!validatePhone()) errors.push("Phone must be exactly 11 digits.");
136+
if (!validatePassword())
137+
errors.push(
138+
"Password must be at least 8 characters, include uppercase, lowercase, and a digit."
139+
);
140+
if (!validateExperience()) errors.push("Select an experience level.");
141+
if (!validateSalary())
142+
errors.push("Expected salary must be a positive number.");
143+
if (!terms.checked)
144+
errors.push("You must agree to the terms & conditions.");
145+
146+
if (errors.length > 0) {
147+
alert(errors.join("\n"));
148+
e.preventDefault();
149+
}
150+
});
151+
});

0 commit comments

Comments
 (0)