Skip to main content
Version: 1.2.x

Form components

Forms provide the most common control styles used in forms, including input, textarea, select, checkbox, radio and switch.

Group & Inline

The two components and can be used tomanage the flow of elements like label, inputs and validation texts.
In some case, the class can be replace by the utility class to add some margin.

This field is required
Are you a front-end developer?
<div class="c-form__group">
<label class="c-form__label" for="test">Test</label>
<input class="c-form__control" type="text" id="test" name="test" required />
<span class="c-form__text">This field is required</span>
</div>

<fieldset class="c-form__group">
<div class="c-form__inline">
<legend>Are you a front-end developer?</legend>
<div class="c-form__toggle">
<input class="c-form__toggle-input" type="radio" name="tg" id="tg1" />
<label class="c-form__toggle-label" for="tg1">Yes</label>
<input class="c-form__toggle-input" type="radio" name="tg" id="tg2" />
<label class="c-form__toggle-label" for="tg2">No</label>
</div>
</div>
</fieldset>

Label

Since v1.0.0

The .c-form__label class add some aesthetic styles like font-weight and adjust the vertical rhythm.

<label class="c-form__label" for="my-label">My label</label>

Controls (a.k.a. Input and Textarea)

Since v1.0.0

The .c-form__control component can be use both on input (text, email, password...) and textarea.

<div class="c-form__group">
<label class="c-form__label" for="name">Name</label>
<input class="c-form__control" type="text" id="name" name="name" placeholder="Name">
</div>

Select

Since v1.0.0
<div class="c-form__group">
<select name="list" id="list" class="c-form__select">
<option value disabled selected>Choose an option</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
...
</select>
</div>

Choice fields

Checkbox

Since v1.0.0
<div class="c-form__group">
<div class="c-form__check">
<input class="c-form__check-input" type="checkbox" name="checkfield" id="check1" required>
<label class="c-form__check-label" for="check1">Option 1</label>
</div>
<div class="c-form__check">
<input class="c-form__check-input" type="checkbox" name="checkfield" id="check2">
<label class="c-form__check-label" for="check2">Option 2</label>
</div>
</div>

Radio

Since v1.0.0
Gender
<fieldset class="c-form__group">
<legend class="c-form__label">Gender</legend>
<div class="c-form__check">
<input class="c-form__check-input" type="radio" name="gender" id="male" required>
<label class="c-form__check-label" for="male">Male</label>
</div>
<div class="c-form__check">
<input class="c-form__check-input" type="radio" name="gender" id="female">
<label class="c-form__check-label" for="female">Female</label>
</div>
</fieldset>

Switch

Since v1.1.0

This component is an alternative style for checkbox inputs.

Toggle

Since v1.0.0

The toggle component allow a specific display for radio inputs when the possible choice are like "true/false" answers.

Are you sure?
<fieldset class="c-form__group">
<div class="c-form__inline">
<legend>Are you sure?</legend>
<div class="c-form__toggle">
<input class="c-form__toggle-input" type="radio" name="toggle" id="toggle1">
<label class="c-form__toggle-label" for="toggle1">Yes</label>
<input class="c-form__toggle-input" type="radio" name="toggle" id="toggl2">
<label class="c-form__toggle-label" for="toggl2">No</label>
</div>
</div>
</fieldset>

Range

Since v1.1.0
<label for="range-sample" class="c-form__label">Select a range</label>
<div class="c-form__range">
<input class="c-form__range-input" type="range" name="range-sample" id="range-sample">
</div>

Inputs range can have several attributes like min and max to overrides default values (0 to 100). The step attribute allow to change the granularity that the value must respect.

You will find more example on the MDN docs.

Display selected value

By default, an range input doesn't prompt the "value" of the field. If some webkit-based browsers offer hash marks, that may not be enough.

To display the value, you can add some tricks using the <output> element.

5
<!-- Option 1: Add JS script on the `<form>` element -->
<form oninput="result.value=parseInt(r.value, 10)">
<div class="c-form__range">
<input
class="c-form__range-input"
type="range" id="r" value="5" min="0" max="10" step="1"
>
<output class="c-form__range-result" name="result" for="r"></output>
</div>
</form>

<!-- Option 2: Add script on the `<input>` element -->
<div class="c-form__range">
<input
class="c-form__range-input"
type="range" id="r" value="5" min="0" max="10" step="1"
oninput="this.nextElementSibling.value=parseInt(this.value, 10)"
>
<output class="c-form__range-result" name="result" for="r"></output>
</div>

File

Since v1.0.0
Add a profile picture
<div class="c-form__group"><span class="c-form__label">Add a profile picture</span>
<input class="c-form__file-input" type="file" name="picture" id="picture" data-multiple-caption="{count} files selected" multipl required>
<label class="c-form__file-label" for="picture">
<strong>Choose a file</strong>
<span></span>
</label>
</div>

Next, you can add this simple JavaScript script to automatically update the input field with the name of the file(s) selected.

<script>
const getNextSibling = (el, selector) => {
let sibling = el.nextElementSibling

// If there's no selector, return the first sibling
if (!selector) return sibling

// If the sibling matches our selector, use it
// If not, jump to the next sibling and continue the loop
while (sibling) {
if (sibling.matches(selector)) return sibling

sibling = sibling.nextElementSibling
}

return sibling
}

if (document.querySelector('input[type=file]')) {
Array.prototype.forEach.call(
document.querySelectorAll('input[type=file]'),
(input) => {
const label = getNextSibling(input, 'label')

input.addEventListener('change', (e) => {
label.querySelector('span').innerHTML = 'Loading...'

if (e.target) {
let text = ''
const { files } = input
const multipleText =
input.getAttribute('data-multiple-caption') ||
'{count} files selected'

if (files && files.length > 1) {
text = multipleText.replace('{count}', files.length.toString())
} else {
text = e.target.value.split('\\').pop()
}

if (text) {
label.querySelector('span').innerHTML = text
}
}
})
},
)
}
</script>

Helpers

Since v1.0.0

You can add some indications by adding texts below fields using the .c-form__text class.

Help texts should be associated with the .c-form__control element related to using the aria-describedby attribute.

This field is required
<div class="c-form__group">
<label class="c-form__label" for="username">Username</label>
<input class="c-form__control" type="text" id="username" name="username" aria-describedby="usernameHelpText" required>
<span class="c-form__text" id="usernameHelpText">This field is required</span>
</div>

An other possibility is to use the helper component to display more content inside a tooltip.

The helper will be automatically shown if the form element is focused (works with controls, select and file elements).

You can only use alphanumeric character. You will be able to modiy it later, so don't worry it you don't like anymore your username.
Make the good choice!
Add a profile picture
Get better results by adding a profile picture
<div class="c-form__group">
<label class="c-form__label" for="username">Username</label>
<input class="c-form__control" type="text" id="username" name="username">
<span class="c-form__helper">
<div class="c-form__helper-content">
<span>You can only use alphanumeric character. You will be able to modiy it later, so don't worry it you don't like anymore your username.</span>
</div>
</span>
</div>

Disabled styles

Gender
Active or not checkboxes
Add a profile picture
<div class="c-form__group">
<label class="c-form__label" for="name">Name</label>
<input class="c-form__control" type="text" id="name" name="name" placeholder="Name" disabled>
</div>

<div class="c-form__group">
<label class="c-form__label" for="message">Message</label>
<textarea class="c-form__control" id="message" name="message" placeholder="Add your message" disabled></textarea>
</div>

<div class="c-form__group">
<label class="c-form__label">Choose an option</label>
<select class="c-form__select" name="list" id="list" disabled>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
</div>

<fieldset class="c-form__group" disabled>
<legend class="c-form__label">Gender</legend>
<div class="c-form__check">
<input class="c-form__check-input" type="radio" name="gender" id="male">
<label class="c-form__check-label" for="male">Male</label>
</div>
<div class="c-form__check">
<input class="c-form__check-input" type="radio" name="gender" id="female">
<label class="c-form__check-label" for="female">Female</label>
</div>
</fieldset>

<div class="c-form__group">
<span class="c-form__label">Active or not the checkbox</span>
<div class="c-form__check">
<input class="c-form__check-input" type="checkbox" name="checkfield" id="check" disabled>
<label class="c-form__check-label" for="check">Option 1</label>
</div>
</div>

<div class="c-form__group">
<div class="c-form__switch">
<input class="c-form__switch-input" type="checkbox" name="switch-disabled" id="switch-disabled" disabled>
<label class="c-form__switch-label" for="switch-disabled">Option 2</label>
</div>
</div>

<div class="c-form__group">
<span class="c-form__label">Add a profile picture</span>
<input
class="c-form__file-input"
type="file"
name="picture-disabled"
id="picture-disabled"
data-multiple-caption="{count} files selected"
disabled
>
<label class="c-form__file-label" for="picture-disabled">
<strong>Choose a file</strong><span></span>
</label>
</div>

Validation styles / feedbacks

The validation messages work a bit like the helper texts.
This behavior is greatly inspired by Bootstrap.

Radio (valid)
Radio (invalid)
Checkbox (valid)
Checkbox (invalid)
File (valid)
File (invalid)

The states can be managed by using the .is-valid or .is-invalid classes to the form element.

Other, it's possible to detect the submission of the form and valid it with JavaScript. Then, you need to add the .is-validated class to the form to display feedback messages.

<script>
const forms = document.querySelectorAll('.needs-validation')

// Loop over them and prevent submission
Array.prototype.slice.call(forms)
.forEach(function (form) {
form.addEventListener('submit', function (event) {
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
}

form.classList.add('is-validated')
}, false)
})
</script>