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 (available soon)
This will be 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>
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.
Help texts should be associated with the form control it relates 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>
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>