Use the JavaScript blur event to validate a field after the user moves away from it. A fetch() request sends the form data to PHP, which returns a JSON success or error message beside that field. Radios, checkboxes and the month selector respond to change so their feedback appears reliably.
Try the on-blur validation demo
The demo reserves two user IDs, abcd and efgh, without a database. It also checks the name, selected option, month and terms checkbox. In a real registration form, check user ID availability against your database with a prepared query, and enforce the same rules during actual submission.
The user ID input has a matching userid_div status element. A visible label and aria-describedby connect the input to its feedback.
<label for="userid">User ID</label>
<input name="userid" id="userid"
aria-describedby="userid_div">
<span id="userid_div" aria-live="polite"></span>The complete demo attaches events to the form controls. The user ID example below sends a POST request to the actual ajax-form-validation-demo-code2.php endpoint. Encoding is handled by FormData. An AbortController cancels that field's previous request, while a version check prevents a late response from displaying outdated feedback.
const userIdInput = document.getElementById('userid');
const userIdStatus = document.getElementById('userid_div');
let controller;
let requestVersion = 0;
userIdInput.addEventListener('blur', async () => {
controller?.abort();
controller = new AbortController();
const version = ++requestVersion;
const data = new FormData();
data.set('field', 'userid');
data.set('userid', userIdInput.value);
try {
const response = await fetch('ajax-form-validation-demo-code2.php', {
method: 'POST', body: data, signal: controller.signal
});
if (!response.ok) throw new Error('Request failed');
const result = await response.json();
if (version === requestVersion) {
userIdStatus.textContent = result.message;
}
} catch (error) {
if (error.name !== 'AbortError' && version === requestVersion) {
userIdStatus.textContent = 'Please try again.';
}
}
});Use textContent, not innerHTML, when showing the response message. Never trust client-side checks as the final security control.
The processor accepts only POST requests and validates the requested field. For the reserved user IDs, it returns a JSON result; it does not claim to check a real member table.
<?php
$userid = trim($_POST['userid'] ?? '');
$validFormat = preg_match('/\A[a-zA-Z0-9_]{4,30}\z/D', $userid) === 1;
$available = $validFormat && !in_array(strtolower($userid), ['abcd', 'efgh'], true);
header('Content-Type: application/json; charset=utf-8');
echo json_encode([
'valid' => $available,
'message' => $available ? 'Demo ID available.' : 'Check ID format or availability.'
]);
?>This excerpt explains the user ID check; the complete processor also checks the request method, the field allowlist, each remaining input, and the entire demo form.
Validating individual fields helps users fix mistakes early, but it does not guarantee the complete form remains valid. The demo intercepts the final submit, sends field=all, and displays every field's current server-side result. It deliberately does not save data or create accounts. A production form would repeat validation before any database write, protect state-changing actions against CSRF, and use prepared SQL statements.
textContent.Download the complete on-blur demo
Continue with basic AJAX form validation or return to the AJAX tutorials.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.