Forms

Form Elements

Overview

For a list of form elements, refer to the MDN document. Making Forms Fabulous with HTML5 is another good article that talks specifically about HTML5 form elements.

Naming

Forms and their child elements should not use input names or ids that conflict with properties of a form, such as submit, length, or method. Name conflicts can cause confusing failures. For a complete list of rules and to check your markup for these problems, see DOMLint. So, do not do this: <input type="submit" name="submit" id="submit">

Web Components

A new (gaining usage in 2015) spec for displaying custom elements in a browser could be a great way to display some of the more complicated input elements such as <input type="color"> and <input type="date">. Learn more on the Web Components website. Some pre-built components can be found on the https://customelements.io/ website.

Pattern Attribute

Several of the input types allow for a pattern attribute. You use it to specify a Javascript RegEx for validation. For example, to ensure a valid URL is entered, you can do this:

<input id="url2" type="url" placeholder="http://www.domain.com"
pattern="(http|https|ftp)\:\/\/[a-zA-Z0-9\-\.\/]*">

 

User Interface Considerations

Pseudo-classes

:valid, :invalid

HTML5 introduced default validation for some elements. The brower will apply pseudo-classes for valid and invalid elements. So, you can highlight invalid elements in red, and good ones in green (for example).

:required, :optional

The required and optional pseudo-classes are applied to form elements based on whether or not the required attribute is present. You can then apply styling to those fields. For example:

input:required {
	font-size:2em;
}
input:optional {
	font-style:italic;
	background-color:inherit;
}

<p><label>Full name: <input type="text" size="12" required></label></p>
<p><label>Weight: <input type="text" size="4"></label></p>

Styling Input Elements in Safari

By default, Safari will use its own styling that you can’t override, unless you turn off the default styling. For example, if you want to specify the width and height of checkboxes then use the CSS property:
-webkit-appearance: none;

Tabindex

Setting the tabindex attribute to -1 will remove the control from the tabbing order, but you can still set the focus using JavaScript (element.focus()). Setting it to 0 will use the document order for tabbing, a -1 will not allow tabbing into the element.

Fieldset

You can group related form controls together with the fieldset element. Common examples are to group a list of radio button together. For example:

Choose your gift






<fieldset>
	<legend>Choose your gift</legend>
	<label><input type="radio" name="car">Ferrari Enzo</label><br>
	<label><input type="radio" name="car">Lamborghini Gallardo</label><br>
	<label><input type="radio" name="car">Nissan GT-R</label><br>
	<label><input type="radio" name="car">Acura NSX</label><br>
	<label><input type="radio" name="car">McLaren P1</label><br>
	<label><input type="radio" name="car">Audi R8</label><br>
	<label><input type="radio" name="car">Pagani Zonda</label><br>
	<label><input type="radio" name="car">Audi R8</label>
</fieldset>

If you have trouble styling the fieldset (say when using border-radius or box-shadow) try floating the fieldset.

Formatting a List of Checkboxes or Radio Buttons

By default, radio buttons have horrible alignment when the label text is long enought that it must wrap onto the second line.

Default behavior Fixed

Unfortunately, you will have to structure your HTML (it will still be valid markup) is a specific manner. Namely, the <label> tag must wrap the <input> element vs. using the for attribute.

/* Assumes you are putting your list inside a <fieldset> */
fieldset label {
	display: block;
	margin-left: 30px;
}
fieldset input {
	float:left;
	margin-left: -30px;
}
<fieldset>
	<legend>My List</legend>
	<label><input type="checkbox" name="chk" value="0">
		This is a rather long label that will demonstrate how this looks when wrapped.</label>
	<label><input type="checkbox" name="chk" value="1">
		Again, some dummy text because I can’t think of anythink clever to say right now.</label>
</fieldset>

The astute reader may wonder why I didn’t just use text-indent: -30px; margin-left: 30px; instead. Well, I wasn’t able to get it to work cross-browser and it would be a few pixels off. If anyone can get text-indent to work, I would love to hear about it.

Output

This element is used to store the output of a calculation. It formally defines a relationship between the fields used to get the data required to perform the calculation and an element to be used to display the results. It is also understood as a live region by some assistive technologies (which means that when the content of the <output> element changes, the assistive technology is aware of that change and can react to it).

In this example the text to the right of the slider is displayed inside an output element.

20

<p><label for=size>Size: </label>
	<input type="range" id="size" min="5" max="50" value="20">
	<output id="sizeVal" for="size">20</output>
</p>
<script>
document.getElementById('size').addEventListener("change", function() {
	document.getElementById('sizeVal').innerHTML = this.value;
}, false);
</script>

Detailed Info for Form Controls

TextBoxes

There are times when you want all the text to be selected in a textfield (<input type="text">) after you click it, or after validation. The best way to do that is fire the focus() and select() methods - in that order. For example:

$('#myTextBox').on('click',function() {
 	this.focus();
 	this.select();
});

Radio Buttons

Javascript Interaction

You must work with each individual button to determine anything about a Radio button group. You either need to loop over them (using straight Javascript), or select just the checked item (using jQuery).

Play As:

The jQuery method is: $('input:radio[name="playAs"]:checked').val();

Server-side Interaction

The form will only send one name/value pair to the server. e.g. playAs = $_POST['playAs']; //EXPRT

Checkboxes

A checkbox is created with <input type="checkbox">.

When you need to determine (through JavaScript) whether or not it has been checked, you must look at the checked property, not the checked attribute. The attribute is used to set the initial value when the page loads.

Right way (jQuery):

$('input:checkbox').each(function(){
	if ($(this)[0].checked) {
		//the current checkbox has been checked
	}
		// OR //
	if ($(this).is(:checked)) {
		//the current checkbox has been checked
	}
});

Right way (straight JavaScript):

var chkboxes = document.form1.myCheckboxes;
for (var i=0; i<chkboxes.length; i++) {
	if (chkboxes[i].checked) {
		//the current checkbox has been checked
	}
}

Wrong way:

$('input:checkbox:checked').each(function(){
	//each instance has the attribute checked, but not
	//necessarily has been checked by the user.
});

Note: Dynamically setting the attribute, will change the property.

Processing in PHP

If you have several related checkboxes, give them a name attribute with the characters [] appended to it. For example, you HTML would look like this:

<label><input type="checkbox" name="animals[]">Cat</label>
<label><input type="checkbox" name="animals[]">Dog</label>
<label><input type="checkbox" name="animals[]">Horse</label>
<label><input type="checkbox" name="animals[]">Llama</label>

Then, when you want to process it with PHP you can access like this:

$cat = $_POST['animals'][0];
$dog = $_POST['animals'][1];
$horse = $_POST['animals'][2];
$llama = $_POST['animals'][3];

This works because when you added the [] to the input element’s name, it became an array in PHP that can be iterated over.

Select Element

The Select element (<input type="select">) is rather strait-forward when using a hardcoded list, but you may find the <option> items are dynamically built from an external datasource. In that case, do not use innerHTML to build the list. Sure, that works fine with real browsers, but stupid, stupid Internet Explorer chokes on it. Use this method instead.

var data = [
	{fruit:"Apple",upc:1234},
	{fruit:"Banana",upc:5678},
	{fruit:"Carrot",upc:9054}];
var selectElem = document.getElementById('mySelect');
var newOption;
for (var i=0;i<data.length;i++) {
	newOption = new Option(data[i].fruit, data[i].upc); /* text, value */
	selectElem.add(newOption,null); /* the null means add to end of list */
}

Setting an Option to "Selected"

Use the selectedIndex property of the Select element, or loop through each of the options like this:

$('#role option').each(function() {
	 if (this.value == $td.data('role')) {
		 this.selected = true;
	 }
});

Reading the selected item

document.getElementById('mySelect').value; //works when not a multiple select

If multiple selections are allowed, then loop through them.

Form Submission

Form’s onSubmit event

It is a good idea to validate your form before sending it off to the server, the question is “Where do I place the validation and submission code?”

You could place that in the Submit button’s onClick event or the form’s onSubmit event. The second option is the correct one. There will be problems for screen readers and keyboard navigation if you put your logic in the Submit button’s handler.

Do this:

$("form").submit(function(e) {
	// Validation code goes here
	var failsValidation = myCustomValidation(this);

	if (failsValidation) {
		e.preventDefault(); // Prevents the form submission
	}
});

AJAX and non-Javascript Form Handling

K. Burke describes very well how it is possible to make your AJAX powered site still be friendly for people who have Javascript turned off. To do this, make the form action and method default to the same endpoint that you are POSTing to with Javascript. You are probably returning some kind of JSON object with an error or success message and then redirecting the user in Javascript. Just change your server endpoint to redirect if the request is not an AJAX request. You can do this because all browsers attach an X-Requested-With: XMLHttpRequest HTTP header to asynchronous Javascript requests.

Changing Parameter Names

Don't change the names of the submitted parameters in Javascript - just submit the same names that you had in your form. In jQuery this is easy, just call the serialize method on the form.

var form = $("#form-id");
$.post('endpoint', $(form).serialize(), function(response) {
	// do something with the response.
});

Sending an eMail

Look at the code in this example for one way you can email the results of a form using PHP.

SPRY Fields

SPRY is a JavaScript library created by Adobe to make user interface elements smarter. In the case of form fields, such as textboxes, you can validate the input prior to sending the data to a server. In Dreamweaver, place a SPRY field on your page and then click the blue label above the field. You can now set the validation items for the field. You can choose to validate on “blur”, “change”, and “submit”. Blur is typically when you are exerting extreme control over the field; it almost always better to use the onChange event and onSubmit.

SPRY Validation

There are two aspects to validation - giving the user feedback when the data entered is bad, and preventing form submission when the data is bad. You don’t need to do anything special to make the validation work, it’s baked into the SPRY fields. However, if you need custom validation that SPRY doesn’t provide (or example, if field A has been filled in, then fields B and C are required, otherwise they are not) then you will need to integrate that logic into Adobe’s SPRY library - I did this once but can’t remember how I did it. Damn it.

Date Validation

See the Date Validation page.

HTML5 Form Controls

The previous two sections on SPRY are probably now a moot point given that HTML5 Form elements can handle basic validation. More information coming soon...