HTML <form id="my-form" action="somewhere" method="post"> <div> Telephone: <input type="text" name="phone"> </div> <input type="submit" value="Send"> </form>
A form with a single field and a submit button. Simple enough, but we can do better. First things first, we need to properly label it. So give the phone number field an id and set up a label to it:
HTML <form id="my-form" action="somewhere" method="post"> <div> <label for="phone-field">Telephone:</label> <input type="text" name="phone" id="phone-field"> </div> <input type="submit" value="Send"> </form>
Now when you click or tap on the label, the text box will focus. This also affects accessibility, as screen
readers will associate the label with its field. This will also help with styling; if you want to have all
your field labels the same width and style in the CSS, you can use label
as a selector.
Now, we can do a couple of things to make the field itself better. Depending on the field, you may want
to add a placeholder
attribute to give the user an idea of the format, or an example value. This
field is a phone number field, so I'll make it have a placeholder showing xxx-xxx-xxxx.
The other thing to look at is whether there exists a special HTML input type for the field. In this case,
we can use type="tel"
instead of the default type="text"
. The difference will be
most noticeable on mobile devices. When the user focuses the field, it will pop up a big easy to use numpad
instead of the whole keyboard. If you use type="email"
then they'll get a slightly modified
keyboard that's easier to enter email addresses with, plus some automatic email format validation on submit.
And if any device or browser doesn't support the field type, it will gracefully fall back to a standard text
box, which isn't too bad. So here we are with our new, upgraded telephone field:
HTML <form id="my-form" action="somewhere" method="post"> <div> <label for="phone-field">Telephone:</label> <input type="tel" name="phone" placeholder="xxx-xxx-xxxx" id="phone-field"> </div> <input type="submit" value="Send"> </form>
Now, I'm assuming that the action target is a backend script that will validate the field and return an error message if something's wrong with it. No problem with that if it's just one field, but this is a minimal example. Your form probably has a bunch of fields and it's not very helpful to see all the errors at the top, and have to scan through the form to find out where each error message is coming from.
We'll want the error message to pop up somewhere around the field. Maybe just under it. We'll need a combo
of JavaScript and CSS to get this working. First, let's make a div for the error notification. Add some CSS
to make it display: none
by default when it's empty.
Last part is changing the submit button to a regular button that we can attach a JavaScript event to.
CSS .error-notify { color: #ff0000; font-weight: bold; display: block; } .error-notify:empty { display: none; }
HTML <form id="my-form" action="somewhere" method="post"> <div> <label for="phone-field">Telephone:</label> <input type="tel" name="phone" placeholder="xxx-xxx-xxxx" id="phone-field"> <div class="error-notify" id="phone-error"></div> </div> <input type="button" id="submit-me" value="Send"> </form> <script src="validation.js"></script>
Now onto the JavaScript which will tie this all together.
The validation can be done with regular JavaScript, but you're going to need server-side validation for security reasons, since any client-side validation can be bypassed by a malicious user. So what the form really should do is send the data with AJAX and handle the response to either pop up error messages or show them the result of their submission.
There are a lot of different ways to do this, but the way I prefer is for the backend code to return a
JSON-encoded associative array for all errors, and then parse through the array to insert the error message
via the textContent
attribute of the error notification.
Here's what a response from the server-side validation might look like:
JSON { "response": "ERROR", "errors": { "phone": "Phone number is invalid" } }
I'll leave the backend code out of this tutorial since it could be in any language. We'll just deal with the response.
We'll use addEventListener
to attach the code to the submit button. Then we'll use the
fetch
API to do an AJAX post to the backend validation. The values that we are sending to the
backend can be encoded into the URL to fetch using URLSearchParams
.
The code will start by clearing all the fields' error messages, so we don't have a lingering error message from a previous attempt.
Here is the code for validation.js
JavaScript document.getElementById('submit-me').addEventListener("click", () => { let params = new URLSearchParams(); let fieldlist = [ "phone" ]; for (let i of fieldlist) { document.getElementById(i + "-error").textContent = ""; // Clear existing error messages params.set(i, document.getElementById('my-form').elements[i].value); // There's more involved in getting values from checkboxes, radio buttons, and select menus // But I'll cover that another day } fetch("somewhere", { method: "POST", headers: {"Content-Type": "application/x-www-form-urlencoded"}, body: params.toString() }).then(response => response.json()).then(data => { if (data.response == "APPROVED") alert("Form fields are valid. Do something cool here!"); else { for (let i in data.errors) { // Populate error message for a field document.getElementById(i + "-error").textContent = data.errors[i]; } } }); });
So there we are, a full-featured, accessible form field with AJAX validation.
There are many other things you can consider to make it better, depending on the purpose of the form. Here are some ideas:
- Have the validation run for each field individually as you type. You can modify your backend validation
to do single field validations, and attach a call to that validation to the field's
input
event. - Use background colors in the form field. Typically red is associated with errors and green is valid input.
- Use responsive CSS to have the labels above the fields on smaller screens and beside the fields on wider screens.
- Add some JavaScript that automatically formats data as the user types, such as automatically adding dashes between parts of a phone number.
- Make detailed error messages for certain types of errors that you think people might make on a form so they can more quickly determine how to correct their data.
- If the form is long, make it automatically scroll to the first validation error message if there are errors.
- Add a
datalist
to any text field where you know many of the responses will be within a set list of options. This helps the user to fill it out quickly with an added side benefit of normalizing the data. - Add an HTML
reset
button so that the user can accidentally click it instead of the submit button, clear all their data and have to start again.
Okay, maybe don't do that last one.