Forms
Overview
Online form solution
As a Queensland Government franchise, agency or statutory body, you have access to an online form solution provided through Queensland Online. On the qld.gov.au website or franchise, an embedded form provided via this solution will inherit the SWE styles shown below.
Structure
In the SWE, we approach forms as a list of 'questions' and use an ordered list to structure it. A 'question' may include one or more form inputs/controls. If multiple inputs or controls are included, use a fieldset.
Forms may be divided into multiple sections and individual questions can be grouped.
Be sure to use an appropriate type attribute on all inputs (e.g. email for email address or number for numerical information).
Styles
The latest form styles (shown below) requires the class .qg-forms-v2
to be added to the <form>
element. For radio buttons and checkboxes, add classes .qg-forms-v2__radio
and .qg-forms-v2__checkbox
to the radio or checkbox container.
Layout
Since Bootstrap applies display:block
and width:100%
to almost all form fields, forms will stack vertically by default.
For form layouts that require varied field widths, multiple columns, and additional alignment options, we suggest using the Bootstrap grid classes. Visit Bootstrap's form documentation to find more detailed guidance on form layout.
Text input
Inputs are used to capture short amounts (a single line) of text. Inputs should be accompanied by a label.
Textarea
Textareas are used for multiple lines of text, for example, a comments field.
Checkbox custom theme
Implement this custom checkbox theme by using the class .rc-theme
.
Code
<fieldset> <ol class="questions"> <li> <fieldset> <ul class="choices compact rc-theme"> <li> <input class="regular-checkbox big-checkbox" id="conditions-of-use1" value="true" name="conditions-of-use" type="checkbox"> <label for="conditions-of-use1" class="rc-theme__label"> <span class="rc-theme__label-desc">Lorem ipsum dolor sit amet.</span> </label> </li> <li> <input class="regular-checkbox big-checkbox" id="conditions-of-use2" value="true" name="conditions-of-use" type="checkbox"> <label for="conditions-of-use2" class="rc-theme__label"> <span class="rc-theme__label-desc">Lorem ipsum dolor sit amet.</span> </label> </li> <li> <input class="regular-checkbox big-checkbox" id="conditions-of-use4" value="true" name="conditions-of-use" type="checkbox" disabled=""> <label for="conditions-of-use4" class="rc-theme__label"> <span class="rc-theme__label-desc">Lorem ipsum dolor sit amet.</span> </label> </li> </ul> </fieldset> </li> </ol> <ol class="questions"> <li> <fieldset> <ul class="choices compact rc-theme"> <li> <input id="conditions-of-use5" class="regular-checkbox big-checkbox" value="true" name="conditions-of-use1" type="checkbox"> <label for="conditions-of-use5" class="rc-theme__with-image"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="58" height="58" viewBox="0 0 32 32"> <path class="rc-theme__icon" d="M30.148 5.588c-2.934-3.42-7.288-5.588-12.148-5.588-8.837 0-16 7.163-16 16s7.163 16 16 16c4.86 0 9.213-2.167 12.148-5.588l-10.148-10.412 10.148-10.412zM22 3.769c1.232 0 2.231 0.999 2.231 2.231s-0.999 2.231-2.231 2.231-2.231-0.999-2.231-2.231c0-1.232 0.999-2.231 2.231-2.231z"></path> </svg> <span class="rc-theme__label-desc">Lorem ipsum dolor sit amet.</span> </label> </li> <li> <input id="conditions-of-use6" class="regular-checkbox big-checkbox" value="true" name="conditions-of-use1" type="checkbox"> <label for="conditions-of-use6" class="rc-theme__with-image"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="58" height="58" viewBox="0 0 32 32"> <path class="rc-theme__icon" d="M30.148 5.588c-2.934-3.42-7.288-5.588-12.148-5.588-8.837 0-16 7.163-16 16s7.163 16 16 16c4.86 0 9.213-2.167 12.148-5.588l-10.148-10.412 10.148-10.412zM22 3.769c1.232 0 2.231 0.999 2.231 2.231s-0.999 2.231-2.231 2.231-2.231-0.999-2.231-2.231c0-1.232 0.999-2.231 2.231-2.231z"></path> </svg> <span class="rc-theme__label-desc">Lorem ipsum dolor sit amet.</span> </label> </li> <li> <input id="conditions-of-use8" class="regular-checkbox big-checkbox" value="true" name="conditions-of-use1" type="checkbox" disabled=""> <label for="conditions-of-use8" class="rc-theme__with-image"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="58" height="58" viewBox="0 0 32 32"> <path class="rc-theme__icon" d="M30.148 5.588c-2.934-3.42-7.288-5.588-12.148-5.588-8.837 0-16 7.163-16 16s7.163 16 16 16c4.86 0 9.213-2.167 12.148-5.588l-10.148-10.412 10.148-10.412zM22 3.769c1.232 0 2.231 0.999 2.231 2.231s-0.999 2.231-2.231 2.231-2.231-0.999-2.231-2.231c0-1.232 0.999-2.231 2.231-2.231z"></path> </svg> <span class="rc-theme__label-desc">Lorem ipsum dolor sit amet.</span> </label> </li> </ul> </fieldset> </li> </ol> </fieldset>
Radio custom theme
Implement this custom radio theme by using the class .rc-theme
.
Code
<fieldset> <ol class="questions"> <li> <fieldset> <ul class="choices compact rc-theme"> <li> <input type="radio" name="current-test" value="Yes" required="required" id="current-test-yes-1"> <label for="current-test-yes-1" class="rc-theme__label"> <span class="rc-theme__label-desc">Lorem ipsum dolor sit amet.</span> </label> </li> <li> <input type="radio" name="current-test" value="No" required="required" id="current-test-no-1" > <label for="current-test-no-1" class="rc-theme__label"> <span class="rc-theme__label-desc">Lorem ipsum dolor sit amet.</span> </label> </li> <li> <input type="radio" name="current-test" value="No" required="required" id="current-test-no-2" disabled> <label for="current-test-no-2" class="rc-theme__label"> <span class="rc-theme__label-desc">Lorem ipsum dolor sit amet.</span> </label> </li> </ul> </fieldset> </li> </ol> <ol class="questions"> <li> <p class="mb-0">Example with an SVG icon.</p> <fieldset> <ul class="choices compact rc-theme"> <li> <input type="radio" name="current-test1" value="Yes" required="required" id="current-test-yes"> <label for="current-test-yes" class="rc-theme__with-image"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="58" height="58" viewBox="0 0 32 32"> <path class="rc-theme__icon" d="M30.148 5.588c-2.934-3.42-7.288-5.588-12.148-5.588-8.837 0-16 7.163-16 16s7.163 16 16 16c4.86 0 9.213-2.167 12.148-5.588l-10.148-10.412 10.148-10.412zM22 3.769c1.232 0 2.231 0.999 2.231 2.231s-0.999 2.231-2.231 2.231-2.231-0.999-2.231-2.231c0-1.232 0.999-2.231 2.231-2.231z"></path> </svg> <span class="rc-theme__label-desc">Lorem ipsum dolor sit amet.</span> </label> </li> <li> <input type="radio" name="current-test1" value="Yes" required="required" id="current-test-no"> <label for="current-test-no" class="rc-theme__with-image"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="58" height="58" viewBox="0 0 32 32"> <path class="rc-theme__icon" d="M30.148 5.588c-2.934-3.42-7.288-5.588-12.148-5.588-8.837 0-16 7.163-16 16s7.163 16 16 16c4.86 0 9.213-2.167 12.148-5.588l-10.148-10.412 10.148-10.412zM22 3.769c1.232 0 2.231 0.999 2.231 2.231s-0.999 2.231-2.231 2.231-2.231-0.999-2.231-2.231c0-1.232 0.999-2.231 2.231-2.231z"></path> </svg> <span class="rc-theme__label-desc">Lorem ipsum dolor sit amet.</span> </label> </li> <li> <input type="radio" name="current-test1" value="No" required="required" id="current-test-no1" disabled> <label for="current-test-no1" class="rc-theme__with-image"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="58" height="58" viewBox="0 0 32 32"> <path class="rc-theme__icon" d="M30.148 5.588c-2.934-3.42-7.288-5.588-12.148-5.588-8.837 0-16 7.163-16 16s7.163 16 16 16c4.86 0 9.213-2.167 12.148-5.588l-10.148-10.412 10.148-10.412zM22 3.769c1.232 0 2.231 0.999 2.231 2.231s-0.999 2.231-2.231 2.231-2.231-0.999-2.231-2.231c0-1.232 0.999-2.231 2.231-2.231z"></path> </svg> <span class="rc-theme__label-desc">Lorem ipsum dolor sit amet.</span> </label> </li> </ul> </fieldset> </li> </ol> </fieldset>
Select
Select provides a means to select a single item from a collapsible list. Use of select can help to reduce input errors and screen space. Use it when the customer does not need to see all the options to understand the question.
The first option in the list should be a prompt to make a selection and use the class 'placeholder'.
Date picker
Validation
Client-side validation is built into the SWE template. Fields are validated on change
events and inline validation messages (shown with the label) are updated. All fields are validated on submit
events and warnings are displayed in a summary placed before the form
element.
Validation techniques
- use the
required="required"
attribute on all required fields - use
type="email"
for email fields (note that more than one is not supported) - use
.setCustomValidity( message )
for other validation - be sure to run custom validation on the best events:
- on
click
for radio buttons and checkboxes - on
change
orblur
for text fields, select boxes and textareas.
- on
Example: Email address must be a qld.gov.au address
Code
<li>
<label for="email">
<span class="label">Email</span>
<abbr title="(required)">*</abbr>
</label>
<input type="email" class="form-control" id="customer-email" name="emailField" required="required" />
</li>
- Required fields is provided—use
required="required"
- Email validation is provided—use
type="email"
- Pattern validation is not yet supported (see more below).
- Use custom script to verify email matches pattern.
- Place the custom script after the global footer, or use jQuery's ready event.
Custom validation script
$( '#email' ).bind( 'change', function() {
var emailPattern = /\.qld\.gov\.au$/,
emailField = $( '#email' ),
value = emailField.val()
;
// if there is no value
if ( value === '' ) {
// clear the custom error
emailField[ 0 ].setCustomValidity( '' );
// required field validation will kick in
// test if value matches pattern
} else if ( emailPattern.test( value )) {
// valid
emailField[ 0 ].setCustomValidity( '' );
} else {
// invalid
emailField[ 0 ].setCustomValidity( 'Must be a .qld.gov.au email address' );
}
});
Example: Required checkboxes
In HTML5, specifying required
on any single checkbox requires the user to tick that box. This is useful for agreeing to terms and conditions. However, if you have a group of possible answers and only need the user to select one (or more), it will not work, and will force customers to tick every box.
To require one or more checkboxes are selected you must use custom validation. You can adapt the following code.
Place this script in the footer of the page:
(function( $ ) {
'use strict';
var minOneCheckboxGroups = [ 'flavours' ],
seen = {},
// check that at least one checkbox is checked
minOneCheckboxCheckedCheck = function() {
var checkboxes = $( this.form.elements[ this.name ] ),
validitionMessage = ''
;
// must have 1 item selected
if ( checkboxes.filter( ':checked' ).length === 0 ) {
validitionMessage = 'Must be completed';
}
// set validity on every checkbox in the group (UI isn't updated otherwise)
checkboxes.each(function() {
this.setCustomValidity( validitionMessage );
});
};
// find checkboxes
minOneCheckboxGroups = $( 'input' ).filter(function() {
return $.inArray( this.name, minOneCheckboxGroups ) >= 0;
});
// initial validity for group
minOneCheckboxGroups.each(function() {
if ( ! seen[ this.name ] ) {
seen[ this.name ] = true;
minOneCheckboxCheckedCheck.apply( this );
}
})
// setup event handler
.on( 'change', minOneCheckboxCheckedCheck );
}( jQuery ));
In your form, be sure to run this check when the form is submitted:
<form action="…" method="post" class="form" onsubmit="minOneCheckboxCheckedCheck();">
HTML5 constraint validation API notes
Validation is based off the HTML5 constraint validation API. The SWE template includes a polyfill for older browsers that do implement the API. The polyfill supports the following:
API | Status | Alternative tactics |
---|---|---|
| Not supported | Assume all fields will be validated |
.setCustomValidity( message ) | Supported | - |
.validity.valueMissing | Supported | - |
.validity.typeMismatch |
support for
@type=email
only
|
use
.setCustomValidity for @type=url |
.validity.patternMismatch | Supported | - |
| Not supported |
use
@maxlength
for
input
and
.setCustomValidity
for
textarea |
| Not supported |
use
.setCustomValidity |
| Not supported |
use
.setCustomValidity |
| Not supported |
use
.setCustomValidity |
.validity.customError |
Supported
(set by .setCustomValidity) | - |
.validity.checkValidity() | Supported | - |
.validity.validationMessage |
support (supported for
valueMissing
,
customError
and
typeMismatch
for
email
)
| .setCustomValidity
will set
validationMessage |
Error messages
Error messages are used to notify the customer when a form field has not passed validation. Briefly describe the action the customer should take to correct each error before they submit the form again.
Use clear and positive language to explain what went wrong and how to fix it—focus on the solution, not the problem. Our suggestions are a guide only. Use messages that work for your customers.
Validation constraint | Suggested error message |
---|---|
Required field is blank |
|
Data is in the wrong format |
|
Value outside range limits |
|
Hint text
Use hint text to provide inline instructions that help the customer understand and answer the question. Hints are optional.
Hint text is useful:
- displaying required data formats (we recommended you use an example). If you support multiple data formats, display the most common one—do not describe them all
- displaying example data
- short instructions
- links to more detailed help.
Further help information
Questions should be designed so customers can easily answer them. We should not expect customers to read help, but it can be provided when useful.
Help content must be published in either an aside on the form itself, or in a separate page.
You can link to help within a hint. The hint text should try to provide enough information if possible, with the help link providing supplemental and more detailed information. Links to help should use a class of help
.
We recommend that help links open in a lightbox/pop-up.
Code
<!-- Hint text --> <form class="qg-forms-v2"> <ol class="questions"> <li> <label for="car-make-model"> <span class="label">Car make and model</span> <small class="hint">Example: Holden Commodore, Toyota Camry</small> </label> <input class="form-control" label="Car make and model" type="text"></input> </li> </ol> </form> <!-- Further help --> <form class="qg-forms-v2"> <ol class="questions"> <li> <label for="card-security-code"> <span class="label">Card security code</span> <small class="hint">3- or 4-digit code on the back of your card. <a class="help" href="#">What is a card security code?</a> </small> </label> <div class="form-row"> <div class="col-3 col-md-2"> <input class="form-control" label="Card security code" type="text" maxlength="4" size="4"></input> </div> </div> </li> </ol> </form>
reCAPTCHA
The SWE code for Google reCAPTCHA includes both the version 3 and version 2, the SWE footer feedback form uses the version 3.
Multiple reCAPTCHAs can be loaded on the same page.
To enable reCAPTCHA on a form with the default SWE Google reCAPTCHA key, set data-recaptcha=true
.
You can set a custom key by using the attribute data-sitekey="KEY"
. For the feature to work, the combination server key must be used on the form submission handler.
View the GitHub repository for code implementation examples.
Additional usage guidance
Use a label
or legend
for the question. Questions don't need to be literally phrased as questions, often a simple prompt is fine (e.g. Email). Don't include a colon at the end of a prompt. Do include a question mark if your prompt is phrased as a question.
EmailWhat is your email address
EmailEmail:
How many baby capsules do you need to hire?How many baby capsules do you need to hire
Example: 'Either or' questions
Customers may have the option to answer one question or another. You can use progressive disclosure (present the options using radio buttons, and then display the relevant questions when the customer clicks the radio button) or use the 'xor' pattern. Progressive disclosure is the better choice if the fields are required.
<ol type="A" class="xor">
<li>
<h2>Queensland Government account</h2>
<p>You’ll only need to confirm your identity once, instead of each time for each Queensland Government services.</p>
<ul class="actions">
<li>
<strong>
<a href="#" class="button">Register</a>
</strong>
</li>
<li>
<a href="#" class="button">Log in</a>
</li>
</ul>
</li>
<li>
<h2>Other provider</h2>
<ul class="actions">
<li>
<em>
<a href="#" class="button">Use provider account</a>
</em>
</li>
</ul>
</li>
</ol>
- The last 'question' in a form is which action to take. There should be only one primary action per form, presented as a button. Primary actions should have a distinct style. Secondary actions may be presented as buttons or links.
- Button actions should be presented as a list.
- Buttons can be
<input type="submit">
,<button>
or<a class="qg-btn">
- To style a link as a button, use
class="qg-btn"
- To create a primary action (green button), surround the input with
<strong>
tags. - An alternate blue primary action is available by surrounding the input with
<em>
tags. Guidelines for when to use the alternate style are to be determined, please contact the Queensland Online if you wish to use this style. Note that the alternate primary action style is not to be used for secondary actions (which are usually grey). - To restrict duplicate submission of forms, add
data-singlesubmit="true"
attribute to the form element. This opt-in method, disables the submit button after form submission.
Sometimes you will want to collect an answer in multiple fields—for example, an address broken down by street lines 1–3, suburb, state and postcode. You must group these questions using a fieldset
and provide a label for the entire group using legend
. Groups may be nested.
Class | Purpose |
---|---|
.group | A group of questions. |
.compact | Use a compact (single line) layout for the group (commonly used for suburb, state and postcode). Does not require a fieldset and legend. |
.atomic | Treat the group as a single question when displaying validation warnings. Must have an wrapping fieldset and legend. |
Refer to Information access and use policy (IS33) for guidance on information privacy.
Customers may use autofill features in their browsers to fill out personal information. To support this, it is important to follow common (or US-based) conventions for labels and fields (e.g. 'city' for town/suburb). It is also important to note that when autofill is used, it does not fire change
, blur
or keypress
events on fields. If you are using custom validity checks, you should always test the .value
property, and must not rely on events to detect user input.
Showing sections of a form one at a time (e.g. step-by-step wizard)
Server side implementation is recommended. Do not use the relevance script provided with the SWE as it will not submit the form fields that are hidden.
Hiding irrelevant questions
The SWE includes a script to toggle relevance on any element. Relevance can be applied to individual questions or entire sections of forms.
Important note that irrelevant questions:
- are not displayed to the user
- will not be validated (e.g. required fields can be blank when they are irrelevant)
- will not be present when the user submits the form.
Best practice is to ask a closed question (use radio buttons) that toggles whether the next question (or section) is relevant. Relevance must be checked:
- when the closed question is changed
- when the form is loaded (browsers may keep radio buttons checked when a form is refreshed).
Relevance can be implemented with custom scripting or text based instructions. Place the custom script after the page footer, or use jQuery's ready event.
Example: Custom script to hide email unless the customer asks for a reply
<li>
<fieldset>
<legend>
<span class="label">Would you like a reply?</span>
<abbr title="(required)">*</abbr>
</legend>
<ul class="choices compact">
<li><input type="radio" name="replyRequested" id="reply-requested-yes" value="yes" /><label for="reply-requested-yes">Yes</label></li>
<li><input type="radio" name="replyRequested" id="reply-requested-no" value="no" /><label for="reply-requested-no">No</label></li>
</ul>
</fieldset>
</li>
<li>
<label for="email">
<span class="label">Email</span>
<abbr title="(required)">*</abbr>
</label>
<input type="email" id="customer-email" name="emailField" required="required" size="40" />
</li>
If you are only hiding one question, you can set relevance on any form field within that control. The SWE template will show/hide the entire question.
$( '#email' ).relevance( 'relevantWhen', { name: 'replyRequested', value: 'yes' });
Example: Custom script to hide a contact us section
If you want to toggle the relevance of an entire section, rather than just a single question, you need to use a jquery selector to specify the section. Sections within forms should be marked up as <li class="section">
, so it should be as simple as $( '#email' ).closest( '.section' )
; Alternatively, you can give your section an @id
and reference that.
$( '#email' ).closest( '.section' ).relevance( 'relevantWhen', { name: 'replyRequested', value: 'yes' });
The is an instructions-based API that requires no scripting. Place instructions into the form control to indicate the conditions when a question is relevant.
<li>
<fieldset>
<legend>
<span class="label">Would you like a reply?</span>
<abbr title="(required)">*</abbr>
</legend>
<ul class="choices compact">
<li><input type="radio" name="replyRequested" id="reply-requested-yes" value="yes" /><label for="reply-requested-yes">Yes</label></li>
<li><input type="radio" name="replyRequested" id="reply-requested-no" value="no" /><label for="reply-requested-no">No</label></li>
</ul>
</fieldset>
</li>
<li>
<label for="email">
<span class="label">Email</span>
<abbr title="(required)">*</abbr>
<small class="relevance">(If you chose ‘Yes’ above)</small>
</label>
<input type="email" id="customer-email" name="emailField" required="required" size="40" />
</li>
This form is composed of a Google auto-suggest location field and other address fields (Street address, City, State, Postal code, Country). When user selects a location in location field, corresponding address fields will be filled by the javascript.
This functionality can be implemented by placing the code below in your template.
Example: via SSI
<!--#include virtual="https://www.qld.gov.au/includes/dynamic/forms/location-autocomplete.html"-->
Example: via HTML template
<li class="text location">
<label for="location-autocomplete">
<span class="label">Location or postcode</span>
</label>
<input type="text" name="location" id="location-autocomplete" class="location-autocomplete" size="30" value="" placeholder="Enter location or postcode" />
<!--#include virtual="/assets/includes/dynamic/maps/get-current-location.html" -->
<ol class="address-autocomplete questions">
<li>
<label for="street">
<span class="label">Street address</span>
</label>
<input type="text" data-type="street" disabled="disabled" id="street" name="street">
</li>
<li>
<label for="city">
<span class="label">City</span>
</label>
<input type="text" data-type="city" disabled="disabled" id="city" name="city">
</li>
<li>
<label for="state">
<span class="label">State</span>
</label>
<input type="text" data-type="state" disabled="disabled" id="state" name="state">
</li>
<li>
<label for="zip">
<span class="label">Postal code</span>
</label>
<input type="text" data-type="zip" disabled="disabled" id="zip" name="zip">
</li>
<li>
<label for="country">
<span class="label">Country</span>
</label>
<input type="text" data-type="country" disabled="disabled" id="country" name="country">
</li>
</ol>
</li>