skip to content

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:

  1. Compile fields independently, using their respective templates.
  2. Organise your data into arrays of fieldsets and fields and loop over these arrays, assigning the formFieldset and formField 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.

An example form fields and their labels

There are 2 ways to add fieldsets to your form:

  1. Create a field with the template value of formFieldset and an array of fields using its fields property.
  2. 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.

Legends

"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

An example of form 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.

An example of form error messages

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

An example of form 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

An example of form 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

An example of form hint text

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

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.

An example of form conditional reveal

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

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

An example of form 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

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

An example of form button

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

An example of form 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 a fields array.
  • gap: The gap between the fields; any valid CSS gap value.
  • hideLabel: You can visually hide labels with the hideLabel 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.