Forms
The forms component provides a range of form elements and inputs that allow users to enter information. It also includes error messages. It is designed to make it as simple as possible to create an HTML form.
Demo
{{#with form1}}
{{#with errorSummary}}
{{> formErrorSummary }}
{{/with}}
{{#each fields}}
{{> formField }}
{{/each}}
{{#each fieldsets}}
{{> formFieldset }}
{{/each}}
<div class="c-forms__field c-forms__inline-fields">
{{#each buttons}}
{{> eds-c-button template=this.template}}
{{/each}}
</div>
{{/with}}
When to use this component
Use the forms component when users need to submit information or data. This could be in order to complete a task or as part of a service we provide. For example, when an author needs to enter the title of their manuscript when submitting to a journal.
How it works
The forms component does not include any JavaScript. States (such as an invalid/error state) are defined at a data level. If you're using client-side processing, you might benefit from compiling the form’s handlebars template in the browser.
Installation
To install the components, go to the get started guide for developers.
To use the Form component, enter the following command in your Terminal:
npm install @springernature/elements
Styles
Include the necessary Sass files in your project:
// theme
@import '/path/to/elements/themes/springernature/scss/enhanced';
// components
...
@import '/path/to/elements/components/forms';
Templates
You can:
- Compile fields independently, using their respective templates.
- Organise your data into arrays of fieldsets and fields and loop over these arrays, assigning the
formFieldset
andformField
partials respectively.
Here is a basic example of implementation:
<form id="my-form" action="/something">
{{#each fields}}
{{> formField}}
{{/each}}
</form>
For this example, you might have 2 simple inputs for a name and password:
"fields": {
[
{
"template": "../forms/formText",
"label": "Your name",
"id": "your-name",
"name": "your-name",
},
{
"template": "../forms/formPassword",
"name": "password",
"label": "Your password",
"id": "password"
}
]
}
Fields and fieldsets
Fields
Form fields are made up of a control (the input) and an associated label. They can also include hint text to provide extra guidance when filling out a field.
The template
property sets the type of field - for example, "template": "formText"
renders a text input field if that is what you have registered the formText.hbs template as.
This component supports several standard form field attributes. For example, to include a readonly
attribute on your text input, you can include a property of the same name on the data:
{
"template": "../forms/formText",
"styleModifier": "formText",
"label": "Your email address",
"id": "your-email",
"name": "your-email",
"readonly": true
}
Fieldsets
Use a fieldset to group fields together under its fields
property. Use a legend
property to label the fieldset itself.
There are 2 ways to add fieldsets to your form:
- Create a field with the template value of
formFieldset
and an array of fields using itsfields
property. - Create an array of fieldsets and loop over them, assigning the formFieldset partial.
(1) The fieldset field
{
"template": "../forms/formFieldset",
"legend": "<h1>Login</h1>",
"fields": [
...
]
(2) A fieldset array
In this case, each fieldset is an object:
"fieldsets": [
{
"legend": "<h2>One fieldset</h2>",
"fields": [
...
]
},
{
"legend": "<h2>Another, different fieldset</h2>",
"fields": [
...
]
}
]
And the accompanying template would apply the formFieldset
partial to each fieldset:
{{#each fieldsets}}
{{> formFieldset}}
{{/each}}
Legends
Use HTML to style the legend and add semantic meaning. In most cases, legends should be headings, with the heading level determined by the page structure.
"fieldsets": {
[
{
"legend": "<h2>My level 2 legend</h2>",
"fields": [
...
]
}
]
}
Do not use a fieldset without an accompanying legend. If a legend is not appropriate, neither is a fieldset; just use fields without a fieldset parent.
A fieldset can include one or more nested fieldsets. If you are including headings in your fieldsets, be careful to use a heading level that reflects the nesting level. For example, if a fieldset’s legend uses <h2>
, any child fieldset within it should use <h3>
or no heading level at all.
Validation
Required and optional fields
Avoid asking for information unless you really need it. To support this, form fields are set to required
by default.
You do not need to mark fields as required. If a user tries to submit the form without filling in a required field, browser validation will show them an error message.
If you need to ask for optional information, set optional: true
. This will remove required
and aria-required="true"
and append the text “(optional)” to the field’s label.
Error messages
Error messages inform the user when there’s a problem with the information they’ve provided and how they can fix it.
Error messages are displayed inline, underneath the label and above the input of the relevant field. Error messages are prefixed with a cross icon. This helps to make the error more obvious to users who cannot perceive the red colour.
Each field can have an error
property. The inclusion of the property means the field is in an error state. The property value (a string) defines the error message the user sees.
{
"template": "../forms/formText",
"label": "Full name",
"id": "full-name",
"name": "full-name",
"error": "Enter your name"
}
Error summary
Summarise errors using a top level errorSummary
property. Each error in the errors array must point to the id
of the input it relates to and repeat its error
message:
"errorSummary": {
"id": "summary",
"title": "There is a problem",
"errors": [
{
"id": "full-name-error",
"error": "Enter your full name"
},
{
"id": "checkbox-terms-error",
"error": "Agree to the terms to continue"
}
]
}
Text input
When to use this form element
Use the text input field when you need to let users enter text that’s no longer than a single line, such as their name or email address.
How it works
All text inputs must have visible labels. Labels are positioned above the input and are written in sentence case.
Avoid placeholder text
The text input component does not support placeholder text.
Placeholder text:
- disappears when a user enters information - which makes it hard for some people to remember what it said
- can be mistaken by some users for information they’ve entered
Instead, add a hint above the input, when you need one, using a hint
property.
Hints
The hint
property adds hint text under the main label text but inside the <label>
. This means it is automatically available to screen reader software.
"hint": "Add the funder(s) of your research for this manuscript"
Placing the hint text above the text input will prevent users from mistaking it as a value and skipping the field.
Data properties
Data attributes are supported for unit testing purposes. You can add them using a dataAttrs
array.
{
"template": "../forms/formText",
"label": "Your email address",
"id": "your-email",
"name": "your-email",
"dataAttrs": {
"test": "someValue"
}
}
This would create the following attribution: data-test="someValue"
.
Datalist
Text input fields can have a datalist
property, which lets you implement autocomplete. This takes 2 properties: id
and options
(an array):
"datalist": {
"id": "my-datalist",
"options": [
"monkey",
"horse",
"emu",
"platypus",
"cockroach",
"whale"
]
}
This builds a standard datalist
field, with options
, and associates it with the input. If a datalist
already exists in the markup, provide just the id
and forego the option
property. If you want to use a custom-built autocomplete solution using JavaScript, omit the datalist
property from the field altogether.
Radios
When to use this form element
Use the radios field (formRadios
) when users need to pick a single option from a list.
How it works
Radio groups
Radios define choices with an inputs
array:
{
"template": "../forms/formRadios",
"legend": "How should we contact you?",
"inputs": [
{
"label": "Email",
"value": "Email",
"name": "contact"
},
{
"label": "Phone",
"value": "Phone",
"name": "contact"
}
]
}
Each input in the inputs array must have the same name
value, as shown by name: contact
in the previous example.
Radios are automatically grouped together in a fieldset. Use the legend
property to describe the radio group.
Radios with a conditionally revealed input
You can show users a field when they select a particular radio or checkbox. For example, revealing a text input field to ask a follow up question to the option they’ve selected.
These fields can have any properties of a standard form field. Set these properties using the fields
property, like this:
{
"label": "Email",
"value": "Email",
"name": "contact",
"fields": [
{
"template": "../forms/formText",
"label": "Email address",
"id": "email-address",
"name": "email-address"
}
]
}
Checkboxes
When to use this form element
Use checkboxes to let users pick one or more options from a list.
When not to use this form element
Do not use checkboxes if users can only choose one option. Instead, use radios.
How it works
Unlike radios, which are always used in sets of 2 or more, you can have a single checkbox field. To give users a set of checkbox choices, organise the checkboxes into a fieldset
:
{
"legend": "<h2>Which subject categories apply to your manuscript?</h2>",
"fields": [
{
"template": "../forms/formCheckbox",
"label": "Biological sciences",
"id": "biological-sciences",
"name": "biological-sciences"
},
{
"template": "../forms/formCheckbox",
"label": "Earth and environmental sciences",
"id": "earth-sciences",
"name": "earth-sciences"
},
{
"template": "../forms/formCheckbox",
"label": "Health sciences",
"id": "health-sciences",
"name": "health-sciences"
},
{
"template": "../forms/formCheckbox",
"label": "Physical sciences",
"id": "physical-sciences",
"name": "physical-sciences"
}
]
}
Selects
When to use this form element
Research shows that some people find selects difficult to use.
Only use selects when there’s no other option.
When not to use this form element
Aim to use alternatives such as:
- Radios, for relatively short lists of options
- A text input with autocomplete where the range of options is large
How it works
Select
fields (using the <select>
element) define the user’s options with an options
property, which must be an array. The selected
property can be used to preselect an option:
"options": [
{
"label": "Author affiliation",
"value": "University of Tokyo"
},
{
"label": "University of Tokyo",
"value": "University of Tokyo",
"selected": true
}
]
File upload
When to use this form element
File upload allows users to select and upload a file of their choosing. Use this element when it is a necessary part of a service. For example, an author manuscript as part of the publication process.
How it works
The standard accept
attribute is supported. Use this for filtering out file types that are not applicable for submission.
Buttons
When to use this form element
Use the Button component to let a user perform an action such as:
- Progressing to the next section of a form
- Submitting a completed form
Use the primary button styling for the main call to action on a page.
How it works
A template
of eds-c-button
defines a set of button controls. The type
property for each individual button corresponds to the type
HTML attribute. For example, here is how you would include a submit button:
"buttons": [
{
"template": "../eds-c-button/eds-c-buttonPlain",
"variant": "primary",
"type": "submit",
"text": "Submit"
},
{
"template": "../eds-c-button/eds-c-buttonPlain",
"variant": "secondary",
"type": "button",
"text": "Delete everything"
}
]
The variant
property is a string. Possible values are:
- primary
- secondary
- tertiary
For more info on Button usage, see documentation for Button component.
Hidden inputs
How it works
You can hide any field from visibility (also from screen reader software and keyboard interaction) using hidden: true
. If you want to use a field of type="hidden
", you need to use template: formHidden
. It is recommended you also apply hidden: true
to such fields because it will remove the inter-field margin. In the following example, note the label
is omitted since hidden fields are not user facing.
{
"template": "../forms/formHidden",
"id": "hidden-field",
"name": "hidden-field",
"hidden": true,
}
Inline fields
When to use this form element
Use inline fields when you need to ask users for information that is part of a continuous set, such as a date or credit card number.
When not to use this form element
Do not use inline fields for an entire form, as this will make it harder for users to scan the page.
How it works
Display fields in a horizontal line using the following template
value:
"template": "../forms/formInlineFields"
For example, here’s a possible field definition for a search bar, comprising an input and submit button:
{
"template": "../forms/formInlineFields",
"gap": "1em",
"buttons": [
{
"template": "../eds-c-button/eds-c-buttonPlain",
"variant": "primary",
"type": "submit",
"text": "Search"
}
],
"fields": [
{
"template": "../forms/formText",
"styleModifier": "formText",
"name": "search",
"id": "search",
"label": "Search",
"hideLabel": true
}
]
}
buttons
: array of Button components that you need for letting the user perform an action.fields
: Individual fields are defined in afields
array.gap
: The gap between the fields; any valid CSSgap
value.hideLabel
: You can visually hide labels with thehideLabel
property without removing them from screen reader output. Only do this if there is another visual form of label (the “Search” label of the submit button in this case).nowrap
: Not used in the previous example. Stop the individual fields from wrapping (beware of narrow viewports).
You can use styleModifier: "formText"
if you want the text field to take all the available space.
Help improve this page
If you’ve got a question, idea or suggestion about how to improve this component or guidance, post in the #ask-Elements Slack channel.