Now that your basic form structure is solid, it is time to guide users by checking their input and showing helpful feedback. Even if the server validates again, clear client-side rules lower user fatigue.
Key terms
- Form validation: checking whether input values follow the rules before submission.
- Regular expression (regex): a pattern used to verify formats like an email address.
blur: the event fired when an input loses focus, often used to validate after typing.aria-live: accessibility attribute that tells assistive tech to read live messages.aria-invalid: signals to assistive tech that the current field is invalid.
Core ideas
- Validation rules: track requirements such as required fields, length, pattern, or matching values.
- Validation timing: decide whether to show messages while typing, on
blur, or at submit time. - Feedback elements: plan warning text, border color, and
aria-liveregions for visual and auditory cues. - Accessibility: attributes like
aria-invalidandaria-live="polite"make sure messages are read aloud.
Code examples
const constraints = {
name: { required: true, minLength: 2 },
email: { required: true, pattern: /^[\w.-]+@([\w-]+\.)+[\w-]{2,}$/ },
password: { required: true, minLength: 8 },
confirmPassword: { matches: "password" },
};
function validateField(name, value, form) {
const rules = constraints[name];
if (!rules) return { valid: true };
if (rules.required && !value.trim()) return { valid: false, message: "This field is required." };
if (rules.minLength && value.length < rules.minLength)
return { valid: false, message: `Please enter at least ${rules.minLength} characters.` };
if (rules.pattern && !rules.pattern.test(value))
return { valid: false, message: "Please follow the requested format." };
if (rules.matches) {
const target = form.elements.namedItem(rules.matches);
if (target && value !== target.value) return { valid: false, message: "Values do not match." };
}
return { valid: true };
}
const form = document.querySelector(".signup-form");
const feedbackEl = document.querySelector(".form-feedback");
form?.addEventListener("input", (event) => {
const target = event.target;
if (!(target instanceof HTMLInputElement) || !form) return;
const { valid, message } = validateField(target.name, target.value, form);
target.classList.toggle("is-invalid", !valid);
target.setAttribute("aria-invalid", String(!valid));
const hint = target.nextElementSibling;
if (hint) hint.textContent = message ?? "";
});
form?.addEventListener("submit", (event) => {
event.preventDefault();
if (!form) return;
const fields = Array.from(form.elements).filter((el) => el instanceof HTMLInputElement);
const invalid = fields
.map((field) => ({ field, result: validateField(field.name, field.value, form) }))
.find(({ result }) => !result.valid);
if (invalid) {
if (feedbackEl) feedbackEl.textContent = invalid.result.message;
invalid.field.focus();
return;
}
if (feedbackEl) {
feedbackEl.textContent = "Sign-up request submitted.";
feedbackEl.classList.add("is-success");
}
});
Splitting real-time and submit-time validation makes it clear what to fix and when.
.signup-form input {
border: 1px solid #c8d0da;
transition: border-color 0.2s ease;
}
.signup-form input.is-invalid {
border-color: #ff5757;
background: rgba(255, 87, 87, 0.1);
}
.signup-form .hint {
font-size: 0.85rem;
color: #ff5757;
min-height: 1.2rem;
}
.form-feedback {
margin-top: 1rem;
font-weight: 600;
}
.form-feedback.is-success {
color: #1ba784;
}
Just a little CSS makes invalid fields obvious.
Replay the flow with BrowserMock
Form validation follows the sequence of input → message → submit, so replaying UI state with BrowserMock, a lightweight mock browser tool, is handy.
const { document, window } = mock(`
<form class="signup-form">
<input name="email" />
<span class="hint"></span>
<div class="form-feedback"></div>
</form>
`);
const form = document.querySelector(".signup-form");
const feedbackEl = document.querySelector(".form-feedback");
form.addEventListener("submit", (event) => {
event.preventDefault();
const { valid, message } = validateField("email", form.email.value, form);
if (!valid) feedbackEl.textContent = message;
});
form.email.value = "broken";
form.dispatchEvent(new window.Event("submit"));
console.log(feedbackEl.textContent); // "Please follow the requested format."
You can confirm that error messages show up right on time without launching a real browser. During reviews, capture BrowserMock console logs to explain state transitions and reach agreement quickly.
Why it matters
- Client-side validation catches mistakes before a request hits the server, saving bandwidth and frustration.
- Clear feedback builds trust for critical flows like admissions or club sign-up forms.
- Accessible messages give the same information to people who rely on assistive tech.
Practice
- Follow along: wire up
validateFieldalong with the input/submit handlers in a single sign-up form. - Extend: add a password-strength meter, phone-number masking, or merge server errors, choosing any two.
- Debug: break the regex or
matchesrule on purpose, watch which message appears, and confirm events do not fire twice in DevTools. - Done when: invalid fields block submission, success text turns green, and there are no console warnings.
Wrap-up
Solid validation makes users trust the experience. Next we will connect web storage and persistence so those inputs stay safe.
💬 댓글
이 글에 대한 의견을 남겨주세요