
Photo by vivek kumar on Unsplash
Forms
Forms are notoriously challenging to style and make accessible. Natura11y provides basic style and behavior for building user friendly, accessible forms.
Form elements include a consistent visible focus for keyboard users.
Include accessible field labels implicitly or explicitly—it's up to you.
intuitively mark required fields. When doing so, Natura11y adds required and data-required attributes automatically.
Checkbox and radio groups use semantic fieldset and legend tags.
Form Entries
The form entry parent selector (.form-entry
) wraps each entry within a form. Child elements within form entries vary depending on their input types. Such types include text inputs, textareas, selects, checkboxes, and radios.
In Figure 1, the .form-entry
selector contains an <input>
field with the type="text"
attribute.
<div class="form-entry">
<label class="form-entry__field">
<span class="form-entry__field__label">
Form Entry Label
</span>
<span class="form-entry__field__input">
<input
type="text"
name="textInputExample"
id="text-input-example"
aria-describedby="help-text-input-example">
</span>
</label>
<small class="form-entry__help" id="help-text-input-example">
Form entry help text
</small>
</div>
Line # | Details |
---|---|
1 | The It contains each entries elements, including help text and feedback messages. When more than one |
3-17 | The It holds the field's label and input elements. The It holds the actual label text, and required indicator (when present). The It holds the field's actual input elements. When using help text, |
19-21 | The Its id equals its associated |
Select Element
With the example in Figure 2, the same .form-entry
container holds a <select>
element.
<div class="form-entry">
<label class="form-entry__field">
<span class="form-entry__field__label">
Form Entry Label
</span>
<span class="form-entry__field__select">
<select
id="select-example"
name="selectExample"
aria-describedby="help-select-example">
<option value="">Select</option>
<option value="Option One">Option One</option>
<option value="Option Two">Option Two</option>
<option value="Option Three">Option Three</option>
<option value="Option Four">Option Four</option>
<option value="Option Five">Option Five</option>
</select>
</span>
</label>
<small class="form-entry__help" id="help-select-example">
Form entry help text
</small>
</div>
Line # | Details |
---|---|
5-7 | The The |
9-21 | The It holds the actual The |
Text Area
Following the previous example's pattern, Figure 3 shows the .form-entry
parent selector with a <textarea>
element.
<div class="form-entry">
<label class="form-entry__field">
<span class="form-entry__field__label">
Form Entry Label
</span>
<span class="form-entry__field__input">
<textarea
rows="8"
name="textInputExample"
id="text-input-example"
aria-describedby="help-textarea-example"
></textarea>
</span>
</label>
<small class="form-entry__help" id="help-textarea-example">
Form entry help text
</small>
</div>
Line # | Details |
---|---|
5-7 | The |
9-16 | The It holds the actual |
File Upload
Natura11y offers a simple file upload component, as shown in Figure 4 below.
<div class="form-entry">
<div class="form-entry__field">
<span class="form-entry__field__label">
Upload a Single File
</span>
<div class="form-entry__field__input">
<label class="file-uploads
<span class="file-uploadsp">
<span class="file-uploadsp__text">Drag and Drop</span>
</span>
<input
class="file-uploadsut"
type="file"
name="fileUploadExample"
id="file-uploadsple"
accept="image/*" />
<span class="button button--outline button--has-icon file-uploadston">
<span class="icon icon-upload"></span>
<span class="button__text">Browse for a File</span>
</span>
</label>
</div>
</div>
<small class="form-entry__help" id="help-file-uploadsple">
Form entry help text
</small>
</div>
Checkboxes
Checkbox (and radio) groups use semantic <fieldset>
and <legend>
tags. They stack vertically, with a healthy amount of padding. This helps to ensure an accessible target size.
Figure 5 provides the markup required to create a checkbox group.
<div class="form-entry">
<fieldset class="form-entry__field">
<legend class="form-entry__field__label">
Form Entry Label
</legend>
<div class="form-entry__option">
<div class="form-entry__option__check">
<label>
<input
type="checkbox"
name="checkboxGroupExample"
id="check-option-one"
value="optionOne">
<span class="option__label">
Option One
</span>
</label>
</div>
<div class="form-entry__option__check">
<label>
<input
type="checkbox"
name="checkboxGroupExample"
id="check-option-two"
value="optionTwo">
<span class="option__label">
Option Two
</span>
</label>
</div>
<div class="form-entry__option__check">
<label>
<input
type="checkbox"
name="checkboxGroupExample"
id="check-option-three"
value="optionThree">
<span class="option__label">
Option Three
</span>
</label>
</div>
</div>
</fieldset>
</div>
Line # | Details |
---|---|
9 | The It holds the options markup for the |
11 | The It holds the actual The |
17-22 | The It includes the |
18-20 | The It holds the actual text label for the checkbox. |
Single Checkbox
For a single checkbox, do not use a <fieldset>
and <legend>
. Instead, provide an id on the .form-entry__field__label
selector (Figure 6, line 5). Then associate it with aria-labeledby
placed on the surrounding <label>
tag (Figure 6, lines 13).
<div class="form-entry">
<div class="form-entry__field">
<span class="form-entry__field__label" id="single-option-label">
Form Entry Label
</span>
<div class="form-entry__option">
<div class="form-entry__option__check">
<label aria-labeledby="single-option-label">
<input
type="checkbox"
name="singleOption"
id="single-option"
value="option">
<span class="option__label">
Option
</span>
</label>
</div>
</div>
</div>
</div>
Checkbox Switch
Checkboxes can transform into switches with just a couple of of changes to the markup.
First, change the .form-entry__option__check
to .form-entry__option__switch
(Figure 7, line 11). Then, above the switch label, add an empty <span>
with a .switch__slider
class (Figure 7, line 19).
<div class="form-entry">
<div class="form-entry__field">
<span class="form-entry__field__label" id="switch-option-label">
Form Entry Label
</span>
<div class="form-entry__option">
<div class="form-entry__option__switch">
<label aria-labeledby="switch-option-label">
<input
type="checkbox"
name="singleOption"
id="switch-option"
value="option">
<span class="switch__slider"></span>
<span class="option__label">
Recieve Notifications
</span>
</label>
</div>
</div>
</div>
</div>
Radios
Like checkboxes, radio groups use semantic <fieldset>
and <legend>
tags.
<div class="form-entry">
<fieldset class="form-entry__field">
<legend class="form-entry__field__label">
Form Entry Label
</legend>
<div class="form-entry__option">
<div class="form-entry__option__radio">
<label>
<input
type="radio"
name="radioGroupExample"
id="radio-option-one"
value="optionOne">
<span class="option__label">
Option One
</span>
</label>
</div>
<div class="form-entry__option__radio">
<label>
<input
type="radio"
name="radioGroupExample"
id="radio-option-two"
value="optionTwo">
<span class="option__label">
Option Two
</span>
</label>
</div>
<div class="form-entry__option__radio">
<label>
<input
type="radio"
name="radioGroupExample"
id="radio-option-three"
value="optionThree">
<span class="option__label">
Option Three
</span>
</label>
</div>
</div>
</fieldset>
</div>
Line # | Details |
---|---|
9 | The It holds each |
11 | The It holds the actual The |
17-22 | The It includes the |
18-20 | The It holds the actual text label for the checkbox. |
Required Fields
Natura11y makes it easy to mark required fields. Add data-required="true"
to the parent .form-group
element of the required field. On the same .form-group
element, include a custom error message using the data-error-message={x}
attribute. Here x equals the message displayed to the user during the validation process.
<div
class="form-entry"
data-required="true"
data-error-message="Custom error message">
<div class="form-entry__field">
...
</div>
</div>
The two data attributes mentioned above are shown in Figure 9, lines 3 and 4. When present on the .form group
selector, Naturally's Javascript adds the necessary required
and data-required
attributes to the form entry's child <input>
element automatically.
With the previous example, notice the red asterisk placed before the label. This too, is added automatically to required fields (via Natura11y's CSS file). The asterisk has become the standard identifier for required fields.
Form Validation
Natura11y provides superficial client-side form validation. Include the novalidate
attribute on the <form>
tag.
<div
class="form-entry"
data-required="true"
data-error-message="Username is required!">
<label class="form-entry__field form-entry__field--float">
<span class="form-entry__field__label">
Username
</span>
<span class="form-entry__field__input">
<input type="text" id="account-username" name="accountUsername">
</span>
</label>
</div>
Floating Labels
For short forms (such as a sign in form) floating labels would be fine to use. Add the .form-entry__field--float
modifier class to the .form-entry__field
selector (see Figure 11, line 6).
<div
class="form-entry"
data-required="true"
data-error-message="Username is required!">
<label class="form-entry__field form-entry__field--float">
<span class="form-entry__field__label">
Username
</span>
<span class="form-entry__field__input">
<input type="text" id="account-username" name="accountUsername">
</span>
</label>
</div>
Related CSS Variables
Further customize Forms by redefining any of their related CSS variables as shown below.
:root {
--form-field-padding-x: var(--spacer-3);
--form-field-padding-y: var(--button-padding-y);
--form-field-border-radius: 0.25em;
}