Vistaprint

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.

There is no wrong answer

This field has an error

Share
Share
jsx
<form class="standard-form">
<label class="stylized-label" for="myExampleTextInput">
Favorite animal <span class="stylized-label-optional">(Optional)</span>
</label>
<div class="input-group">
<input
class="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">
<textarea
class="
stylized-textarea
stylized-textarea-skin-error
stylized-textarea-full-width
input-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 (TextInputDropdown, 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, or TextArea and treat it as the primary "input" element

  • Look for a nested FormLabel, and automatically add the htmlFor attribute to it, using the input's id as a value

  • Look for a nested FormHelper, and automatically add an aria-describedby to the input with the FormHelper's id as a value

  • Look for a nested FormError, and put the error skin on the input. It will automatically add an aria-describedby to the input with the FormError's id as a value, and additionally add an aria-errormessage to the input with the FormError'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 InputTextarea, or Dropdown), an optional piece of helper text, and an optional error message. It provides a standard layout for these elements.

There is no wrong answer

Share
Share
jsx
<form class="standard-form">
<label class="stylized-label" for="myExampleInputGroupInput">
Favorite animal <span class="stylized-label-optional">(Optional)</span>
</label>
<div class="input-group">
<input
type="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.

"Vegetable" can also include fruits and non-edible plants

Share
Share
jsx
<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.

There is no wrong answer

This field has an error

Share
Share
jsx
jsx
<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">
<input
class="stylized-input input-group-input"
type="text"
id="myExampleInput"
/>
</div>
</div>
</div>
</div>
</div>

Components

StandardForm

PropTypeDefaultDescription
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 thecomponentprop(default: <form/>)

FormField

FormField has no props of its own

All props are forwarded to the element specified in thecomponentprop(default: <div/>)

FormLabel

PropTypeDefaultDescription
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 thecomponentprop(default: <label/>)

FormLabelOptional

FormLabelOptional has no props of its own

All props are forwarded to the element specified in thecomponentprop(default: <span/>)

FormInputGroup

FormInputGroup has no props of its own

All props are forwarded to the element specified in thecomponentprop(default: <div/>)

FormHelper

PropTypeDefaultDescription
sizeVariant"standard" | "super" | "mini" | "mega""standard"

The size variation

All other props are forwarded to the element specified in thecomponentprop(default: <p/>)

FormError

PropTypeDefaultDescription
sizeVariant"standard" | "super" | "mini" | "mega""standard"

The size variation

All other props are forwarded to the element specified in thecomponentprop(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 a FormField will provide this. If you are not using FormLabel, 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 a aria-labelledby attribute, or an aria-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 an aria-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, an aria-label attribute whose value is a descriptive title of the group. The value of aria-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 with FormHelper and/or FormError will provide this. If you are not using FormField: the input should have an aria-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 and aria-errormessage attributes whose value is the id of the error message; the React FormField and FormError will provide this. The error message should not be a label tag with a for 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").

Dropdown

Textarea

Text Input