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.
<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
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)
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
<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
<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
<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
This component is an alternative style for checkbox
inputs.
Toggle
The toggle component allow a specific display for radio
inputs when the
possible choice are like "true/false" answers.
<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
<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.
<!-- 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
<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
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.
<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).
<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
<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.
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>