Commentary
The form element provides the most common control styles used in forms, including input,
textarea, select, checkbox, radio and switch. The input
tag is encapsulated in a label
tag that associates the label text with the input field.
Although the form element is a common item, it is challenging to structure because of the wide variety of input types. Also, form validation and submission vary depending on the client side framework employed. Included here is a simple javascript routine to collect and display the form's inputs. Validation is typically handled through javascript before sending to the server.
Long forms are often required for system administration or configuration purposes. An optional tabbed form variant is provided that breaks a long form into tabs that have related inputs. This is all CSS controlled - no javascript required. The form submit button sees all of the form fields and hence all these fields will be sent to the server. Note customers will usually not see these long forms! ... should not see. Just in case, for screen readers, the tab controls are hidden and the full form is semantically structured to be readable by assistive technologies.
Usage
Classes: | |
---|---|
.form |
main form container added to form html tag |
.has-form-shadow |
modifier that adds a shadow and padding to form |
.adjust-label |
shifts field label to the right |
fieldset |
HTML tag that builds an optional collection of inputs such as radio buttons or checkboxes. |
is-vertical |
Optional fieldset modifier aligns children nodes vertically. |
.field-group |
Optional class to create an horizontal display of inputs. |
.field-error |
adds a red border to a field input |
.has-field-addons |
flexbox container for classic grouped inputs |
.is-fullwidth |
Optional class for a label tag in a .has-field-addons
Ensures that this field will fill the available space for this label in a field group |
.has-help-text |
Optional form class to show a help icon in top right of the field. Associated help text will appear below input field. |
.form-footer |
Container for submit and other buttons |
.is-form-tabbed |
Optional modifier for .form class in the form element signifies that this form
contains a tabbed structure. |
.form-tabs |
Master container for the radio buttons that select the .form-group to show as
well as containing the list of tabs text. |
.form-group-container |
Parent container for .form-groups . This is a wrapper to needed to set presentation of
the .form-group s. |
.form-group |
Container for various form fields. The .form-group is moved out of or into the viewport
by clicking on a label in the master container. |
Dependencies: | |
---|---|
File: | form.css |
Variables: | --bg-main-elem, --border-main-darker, --danger, --gap-col, --gap-row, --margin, --mar-horz, --margin-form, --pad-horz, --primary, --radius-elem, --size-6, --size-7, --shadow, --text-elem, --weight-medium, --weight-semibold |
Examples
No Frills Form and Elements
<div class="column">
<form class="form" method="post">
<label class="field-error">
<span>Input Field</span>
<input type="text" placeholder="Text input" name="input_field">
</label>
<label>
<span>Text Area</span>
<textarea rows="3" placeholder="Text area input" name="textarea_field"></textarea>
</label>
<div class="has-help-text">
<span>
<span class="icon-bg-help"></span>
</span>
<label>
<span>Text Area</span>
<textarea rows="3" placeholder="Text area input" name="textarea_field"></textarea>
</label>
<p>Help text for this field.</p>
</div>
<label>
<span>Switch</span>
<span class="switch">
<input type="checkbox">
<span>Toggle Switch Value</span>
</span>
</label>
<label>
<span>Select</span>
<select name="select1_field">
<option value="sel1">Select One</option>
<option value="sel2">Select Two</option>
</select>
</label>
<fieldset>
<legend>Radio Group</legend>
<label>
<input type="radio" name="group1">
<span>One</span>
</label>
<label>
<input type="radio" name="group1">
<span>Two</span>
</label>
<label>
<input type="radio" name="group1">
<span>Three</span>
</label>
</fieldset>
<fieldset>
<legend>Checkbox Group</legend>
<label>
<input type="checkbox" name="group2">
<span>One</span>
</label>
<label>
<input type="checkbox" name="group2">
<span>Two</span>
</label>
<label>
<input type="checkbox" name="group2">
<span>Three</span>
</label>
</fieldset>
<div class="has-field-addons">
<label>
<span class="sr-only">Select Currency</span>
<select name="select2_field">
<option value="dollar">$</option>
<option value="pound">£</option>
<option value="euro">€</option>
</select>
</label>
<label class="is-fullwidth">
<span class="sr-only">Enter Amount</span>
<input type="text" name="currency">
</label>
<button class="is-primary has-hover" aria-label="Search">
Search
</button>
</div>
<div class="has-field-addons">
<button class="is-secondary" aria-label="icon only">
<span class="icon-bg-file"></span>
</button>
<label class="is-fullwidth">
<span>Find File</span>
<input type="file" name="file_field">
</label>
</div>
<div class="has-field-addons">
<label class="is-fullwidth">
<span>Search</span>
<input type="text" name="search_text">
</label>
<button class="is-primary" aria-label="icon only">
<span class="icon-bg-search"></span>
</button>
</div>
</form>
Full Form Structure
<form id="test-form" class="form has-form-shadow" method="post">
<header>Optional Form Title</header>
<label>
<span>Input Field</span>
<input type="text" placeholder="Text input" name="input_field">
</label>
<div class="field-group">
<label class="select">
<span>Select</span>
<select name="select1">
<option value="one">Select One</option>
<option value="two">Select Two</option>
</select>
</label>
<label class="select">
<span>Colour</span>
<input type="color" name="color_field">
</label>
</div>
<div class="field-group">
<label>
<span>Date Field</span>
<input type="date" name="date_field">
</label>
<label>
<span>Time Field</span>
<input type="time" value="09:00" name="time_field">
</label>
</div>
<label>
<span>Input Field</span>
<input type="text" placeholder="Text input" name="text2_field">
</label>
<label>
<span>Switch</span>
<span class="switch">
<input type="checkbox" name="switch_field">
<span>Toggle Switch Value</span>
</span>
</label>
<label>
<span>Select</span>
<select name="select2">
<option value="one">Select One</option>
<option value="two">Select Two</option>
</select>
</label>
<div class="field-group">
<label>
<span>Email Field</span>
<input type="email" required name="email_field">
</label>
<label>
<span>Phone Field</span>
<input type="tel" required name="phone_field">
</label>
</div>
<fieldset>
<legend>Radio Group</legend>
<label>
<input type="radio" name="radio-group1" value="One">
<span>One</span>
</label>
<label>
<input type="radio" name="radio-group1" value="Two">
<span>Two</span>
</label>
<label>
<input type="radio" name="radio-group1" value="Three">
<span>Three</span>
</label>
</fieldset>
<fieldset>
<legend>Checkbox Group</legend>
<label>
<input type="checkbox" name="checkboxes" value="One">
<span>One</span>
</label>
<label>
<input type="checkbox" name="checkboxes" value="Two">
<span>Two</span>
</label>
<label>
<input type="checkbox" name="checkboxes" value="Three">
<span>Three</span>
</label>
</fieldset>
<div class="form-footer">
<button type="submit" class="is-primary has-hover">Submit!</button>
</div>
</form>
<script>
const submit = document.getElementById("test-form");
submit.addEventListener('submit', (ev) => {
ev.preventDefault();
const preamble = "Some simple javascript for demonstration only.\nValues picked up in form:\n\n";
const fields = ["input_field", "select1", "color_field", "date_field", "time_field", "text2_field",
"switch_field", "select2", "email_field", "phone_field", "radio-group1", "checkboxes"];
let out = {};
fields.forEach( field => {
switch(field){
/* a group of checkboxes is annoying to handle, need to use its state to extract values */
case "checkboxes":
out[field] = [];
Object.values(submit2.elements[field]).forEach( box => {
if(box.checked){
out[field].push(box.value);
}
});
break;
/* a checkbox is also a pain in the butt! */
case "switch_field":
out[field] = !!submit2?.elements[field]?.checked;
break;
default:
out[field] = submit2.elements[field].value;
}
});
window.alert( `${preamble} ${JSON.stringify(out, null, ' ')}`);
})
</script>
Tabbed Form Structure
<form id="test-form-tabbed" class="form is-form-tabbed" method="post">
<header class="is-secondary">Tabbed Form</header>
<div class="form-tabs">
<input type="radio" name="tab_unit_01" id="tabs_content_01" hidden checked aria-hidden="true">
<input type="radio" name="tab_unit_01" id="tabs_content_02" hidden aria-hidden="true">
<input type="radio" name="tab_unit_01" id="tabs_content_03" hidden aria-hidden="true">
<ul hidden aria-hidden="true">
<li><label for="tabs_content_01">One</label></li>
<li><label for="tabs_content_02">Two</label></li>
<li><label for="tabs_content_03">Three</label></li>
</ul>
<div class="form-group-container">
<div class="form-group" id="one">
<label>
<span>Input Field</span>
<input type="text" placeholder="Text input" name="input_field">
</label>
<div class="field-group">
<label class="select">
<span>Select</span>
<select name="select1">
<option value="one">Select One</option>
<option value="two">Select Two</option>
</select>
</label>
<label class="select">
<span>Colour</span>
<input type="color" name="color_field">
</label>
</div>
<div class="field-group">
<label>
<span>Date Field</span>
<input type="date" name="date_field">
</label>
<label>
<span>Time Field</span>
<input type="time" value="09:00" name="time_field">
</label>
</div>
</div>
<div class="form-group" id="two">
<label>
<span>Input Field Two</span>
<input type="text" placeholder="Text input" name="text2_field">
</label>
<label>
<span>Switch</span>
<span class="switch">
<input type="checkbox" name="switch_field" value="toggle-on">
<span>Toggle Switch Value</span>
</span>
</label>
<label>
<span>Select</span>
<select name="select2">
<option value="one">Select One</option>
<option value="two">Select Two</option>
</select>
</label>
<div class="field-group">
<label>
<span>Email Field</span>
<input type="email" name="email_field">
</label>
<label>
<span>Phone Field</span>
<input type="tel" name="phone_field">
</label>
</div>
</div>
<div class="form-group" id="three">
<fieldset>
<legend>Radio Group</legend>
<label>
<input type="radio" name="radio-group1" value="One">
<span>One</span>
</label>
<label>
<input type="radio" name="radio-group1" value="Two">
<span>Two</span>
</label>
<label>
<input type="radio" name="radio-group1" value="Three">
<span>Three</span>
</label>
</fieldset>
<fieldset>
<legend>Checkbox Group</legend>
<label>
<input type="checkbox" name="checkboxes" value="One">
<span>One</span>
</label>
<label>
<input type="checkbox" name="checkboxes" value="Two">
<span>Two</span>
</label>
<label>
<input type="checkbox" name="checkboxes" value="Three">
<span>Three</span>
</label>
</fieldset>
</div>
</div>
</div>
<div class="form-footer">
<button type="submit" class="is-primary has-hover">Submit!</button>
</div>
</form>
<script>
const submit = document.getElementById("test-form");
submit.addEventListener('submit', (ev) => {
ev.preventDefault();
const preamble = "Some simple javascript for demonstration only.\nValues picked up in form:\n\n";
const fields = ["input_field", "select1", "color_field", "date_field", "time_field", "text2_field",
"switch_field", "select2", "email_field", "phone_field", "radio-group1", "checkboxes"];
let out = {};
fields.forEach( field => {
switch(field){
/* a group of checkboxes is annoying to handle, need to use its state to extract values */
case "checkboxes":
out[field] = [];
Object.values(submit2.elements[field]).forEach( box => {
if(box.checked){
out[field].push(box.value);
}
});
break;
/* a checkbox is also a pain in the butt! */
case "switch_field":
out[field] = !!submit2?.elements[field]?.checked;
break;
default:
out[field] = submit2.elements[field].value;
}
});
window.alert( `${preamble} ${JSON.stringify(out, null, ' ')}`);
})
</script>