Form
Our Standard Form wraps a series of Input Group elements and their labels, providing a standardized layout for the form elements. The React components for these also provide accessibility support automatically.
Playground
Standard Form
Standard Form wraps a series of Input Group components and their labels, providing a standardized layout and spacing for them.
<StandardForm><FormField><FormLabel>Favorite animal <FormLabelOptional>(Optional)</FormLabelOptional></FormLabel><FormInputGroup><TextInput /><FormHelper>There is no wrong answer</FormHelper></FormInputGroup></FormField><FormField><FormLabel>Why do you like that animal?</FormLabel><FormInputGroup><TextArea fullWidth rows={4} /><FormError>This field has an error</FormError></FormInputGroup></FormField></StandardForm>
<form class="standard-form"><label class="stylized-label" for="myExampleTextInput">Favorite animal <span class="stylized-label-optional">(Optional)</span></label><div class="input-group"><inputclass="stylized-input input-group-input"type="text"aria-invalid="false"id="myExampleTextInput"aria-describedby="myExampleHelperText"/><p class="input-group-helper-text" id="myExampleHelperText">There is no wrong answer</p></div><label class="stylized-label" for="myExampleHelperTextarea">Why do you like that animal?</label><div class="input-group"><textareaclass="stylized-textareastylized-textarea-skin-errorstylized-textarea-full-widthinput-group-input"aria-invalid="true"rows="4"id="myExampleHelperTextarea"aria-errormessage="myExampleHelperErrorText"aria-describedby="myExampleHelperErrorText"></textarea><p class="input-group-error-text" id="myExampleHelperErrorText">This field has an error</p></div></form>
Form Field
In React Visage, FormField
is a utility component (it does not provide any styling by itself). Its job is to ensure that its children all know about one another, so that they can provide the proper context in the DOM and in the Accessibility Tree.
Inside of the FormField
should be one input (TextInput
, Dropdown
, or TextArea
) and a FormLabel
. Inside of the FormLabel
, we can add a FormLabelOptional
if the field is not required. (Fields are assumed to be required unless marked as optional.)
FormField
will:
Look for a nested
TextInput
,Dropdown
, orTextArea
and treat it as the primary "input" elementLook for a nested
FormLabel
, and automatically add thehtmlFor
attribute to it, using the input's id as a valueLook for a nested
FormHelper
, and automatically add anaria-describedby
to the input with theFormHelper
's id as a valueLook for a nested
FormError
, and put the error skin on the input. It will automatically add anaria-describedby
to the input with theFormError
's id as a value, and additionally add anaria-errormessage
to the input with theFormError
's id.
The vanilla API doesn't have a comparable component for FormField
; you will have to add all these attributes yourself.
Input Group
When used inside a Standard Form, the Input Group groups together an input (a Text Input, Textarea, or Dropdown), an optional piece of helper text, and an optional error message. It provides a standard layout for these elements.
<StandardForm><FormField><FormLabel>Favorite animal <FormLabelOptional>(Optional)</FormLabelOptional></FormLabel><FormInputGroup><TextInput /><FormHelper>There is no wrong answer</FormHelper></FormInputGroup></FormField></StandardForm>
<form class="standard-form"><label class="stylized-label" for="myExampleInputGroupInput">Favorite animal <span class="stylized-label-optional">(Optional)</span></label><div class="input-group"><inputtype="text"class="stylized-input input-group-input"aria-invalid="false"id="myExampleInputGroupInput"aria-describedby="myExampleInputGroupHelperText"/><p class="input-group-helper-text" id="myExampleInputGroupHelperText">There is no wrong answer</p></div></form>
"tight" skin
The "tight" skin for Standard Form puts less vertical space between each Input Group.
<StandardForm skin="tight"><FormField><FormLabel>Favorite animal <FormLabelOptional>(Optional)</FormLabelOptional></FormLabel><FormInputGroup><TextInput /></FormInputGroup></FormField><FormField><FormLabel>Favorite vegetable <FormLabelOptional>(Optional)</FormLabelOptional></FormLabel><FormInputGroup><TextInput /><FormHelper>"Vegetable" can also include fruits and non-edible plants</FormHelper></FormInputGroup></FormField><FormField><FormLabel>Favorite mineral <FormLabelOptional>(Optional)</FormLabelOptional></FormLabel><FormInputGroup><TextInput /></FormInputGroup></FormField></StandardForm>
<form class="standard-form standard-form-skin-tight">etc</form>
Horizontal Layout
In order to render the label next to the input rather than above it, we can make use of the horizontal
variant for Standard Form, combined with our grid system.
First, we render a Grid Container inside of the Standard Form, and we render a separate Row for each field.
(In React, take advantage of the component
property on Row
. Normally, Row
just renders a div
, but we're using the component
prop to tell Row
to render a FormField
instead of a plain div
. The result is a component that is both a Row
and a FormField
.)
Next, inside each Row, we render one column element for the label, and another for the Input Group. Pick column widths as appropriate for your content, but don't set explicit column values on Extra-Small screens. Doing so lets the form assume a vertical arrangement on Extra-Small screens instead.
<StandardForm variant="horizontal"><GridContainer><Row component={FormField}><Column span={3}><FormLabel>Favorite animal <FormLabelOptional>(Optional)</FormLabelOptional></FormLabel></Column><Column span={9}><FormInputGroup><TextInput /><FormHelper>There is no wrong answer</FormHelper></FormInputGroup></Column></Row><Row component={FormField}><Column span={3}><FormLabel><FormLabel>Why do you like that animal?</FormLabel></FormLabel></Column><Column span={9}><FormInputGroup><TextArea fullWidth rows={4} /><FormError>This field has an error</FormError></FormInputGroup></Column></Row></GridContainer></StandardForm>
<StandardForm><GridContainer><Row component={FormField}><Column span={3}><FormLabel>Favorite animal</FormLabel></Column><Column span={9}><FormInputGroup><TextInput /></FormInputGroup></Column></Row></GridContainer></StandardForm>
<div class="standard-form standard-form-horizontal"><div class="grid-container"><div class="row"><div class="col-3"><label class="stylized-label" for="myExampleInput">Favorite animal</label></div><div class="col-9"><div class="input-group"><inputclass="stylized-input input-group-input"type="text"id="myExampleInput"/></div></div></div></div></div>
Components
StandardForm
Prop | Type | Default | Description |
---|---|---|---|
variant | "horizontal" | "vertical" | vertical | The visual variant |
skin | "standard" | "tight" | standard | The visual style of the form |
All other props are forwarded to the element specified in thecomponent
prop(default: <form/>
)
FormField
FormField
has no props of its own
All props are forwarded to the element specified in thecomponent
prop(default: <div/>
)
FormLabel
Prop | Type | Default | Description |
---|---|---|---|
skin | "line" | "standard" | The visual variant | |
sizeVariant | "standard" | "super" | "mini" | "mega" | "standard" | The size variation |
All other props are forwarded to the element specified in thecomponent
prop(default: <label/>
)
FormLabelOptional
FormLabelOptional
has no props of its own
All props are forwarded to the element specified in thecomponent
prop(default: <span/>
)
FormInputGroup
FormInputGroup
has no props of its own
All props are forwarded to the element specified in thecomponent
prop(default: <div/>
)
FormHelper
Prop | Type | Default | Description |
---|---|---|---|
sizeVariant | "standard" | "super" | "mini" | "mega" | "standard" | The size variation |
All other props are forwarded to the element specified in thecomponent
prop(default: <p/>
)
FormError
Prop | Type | Default | Description |
---|---|---|---|
sizeVariant | "standard" | "super" | "mini" | "mega" | "standard" | The size variation |
All other props are forwarded to the element specified in thecomponent
prop(default: <p/>
)
Guidelines
Designer Guidelines
Do not visually indicate that a form field is required; use the default visual state for required fields. If a field is not required, add "(Optional)" inside the label, as shown above.
Accessibility Guidelines
Any input field needs an accessible label; the React
FormLabel
component inside aFormField
will provide this. If you are not usingFormLabel
, you need to add a label, preferably a<label>
tag, with a for attribute whose value is the id of the input. (If a<label>
tag is not possible, the input either needs aaria-labelledby
attribute, or anaria-label
attribute with a localized value.)If an input is a required field, you must add the attribute
aria-required="true"
to the input, to signal to assistive technologies that the field is required.If there is more than one form element in a logical group, they should be grouped together in the code, either with:
a fieldset, or
an element with the attribute
role="group"
. This wrapper element must have anaria-labelledby
attribute whose value is the id of the element that acts as a title for the group — or, if the group does not have a visible title, anaria-label
attribute whose value is a descriptive title of the group. The value ofaria-label
must be localized, as some browsers will read it to the user.
If the input should support autocomplete (e.g. a mailing or shipping address, or credit card entry), then it should have an appropriate value for the
autocomplete
property.When an input field has helper text and/or an error message, that text needs to be associated with the input; the React
FormField
component along withFormHelper
and/orFormError
will provide this. If you are not usingFormField
: the input should have anaria-describedby
attribute whose value is a space-separated list of the ids of the message(s).When an input field has an error, the input should have
aria-describedby
andaria-errormessage
attributes whose value is the id of the error message; the ReactFormField
andFormError
will provide this. The error message should not be a label tag with afor
attribute pointing to the input.While an input's value is invalid, the input should have
aria-invalid="true"
on it.For inputs with buttons beside them or inset inside them, if the button is simply an icon and has no visible text, it will need to provide assistive devices with information on what the button does:
If the button has nearby text that explains what it does, the button should have an
aria-labelledby
attribute whose value is the id of the element that describes it.Otherwise, the button should have an inner
span
that is visually hidden, and whose contents are localized text explaining what the button does (e.g. "Search").