Skip to content
lab components / Forms and input

Form element wrapper

Provides a structured container for form elements, clarifying their purpose, offering context, and displaying feedback consistently.

This is a Lab component!

That means it doesn't satisfy our definition of done and may be changed or even deleted. For an exact status, please reach out to the Fancy team through the dev_fancy or ux_fancy channels.

import { FormElementWrapper } from "@siteimprove/fancylab";

#Examples

#Overview of form elements

ControlUsageExamplesBest practice
Form Element Wrapper Wraps individual input controls to provide consistent styling, labeling, and error handling.A group of radio buttons with a label, help text, and an error message area.
  • Group related elements together visually.
  • Use clear and descriptive labels
  • Provide concise instructions and error messages in close proximity to the input field.
Input Field Captures short, single-line text.Name, email address, phone number, short answer
  • Use the most appropriate input type for the data being collected.
  • Ensure the label clearly describes the expected input.
  • Provide a placeholder as a hint or example.
Checkbox Allows users to select multiple options from a list."Agree to terms and conditions," selecting rows to display in the table, bulk selection
  • Group related options visually.
  • Consider offering a "Select All" option if applicable.
Radios Allows users to select a single option from a list of mutually exclusive choices.Choosing WCAG version, level of WCAG conformance, or display title/ URL
  • Limit the number of options to avoid overwhelming users.
  • Visually group options and use clear, concise labels.
  • If appropriate, pre-select the most common or recommended option.
Toggle Switch Provides a binary choice (on/off, yes/no).Enabling/disabling an AI feature, showing/hiding a section of content, or toggling an enhanced contrast in Chart.
  • Clearly label the on and off states.
  • Use toggle switches sparingly to avoid overwhelming users
File Input Allows users to upload one or more files.Uploading a company logo to customise dashboard report
  • Clearly indicate accepted file types and size limits.
  • Display the selected file name or a preview after selection.
Select Allows users to choose a single option (or multiple in a multi-select variant) from a list.Selecting a country, state, or category from a predefined list.
  • Use a descriptive label for the Select.
  • Order options logically (alphabetically, numerically, or by importance).
  • Consider a searchable Select for long lists.
Text area Captures longer, multi-line text input.Writing a comment, Chart’s annotation providing feedback, or filling out a long-form description.
  • Provide enough space for the expected input.
  • Consider showing a character count or limit.
  • Use placeholder text as a hint or example.

#Default

The default wrapper is ideal for text input fields.

Best Practices:

  • Use specific and descriptive labels (e.g., "Mailing Address" instead of just "Address").
  • Consider using placeholder text to provide examples or hints, but not as a replacement for labels.
const [value, setValue] = useState(""); const [value2, setValue2] = useState(""); return ( <> <FormElementWrapper label="Label" name="name"> <InputField value={value} onChange={setValue} /> </FormElementWrapper> <FormElementWrapper label="Label with tooltip" name="name" tooltip="Some further explanation"> <InputField value={value2} onChange={setValue2} /> </FormElementWrapper> </> );

#Group

If you need to use another component (e.g. a Button) together with a form control you must pass a child with the type of a functional component, spread the props on the form control component (e.g. Input Field) and add the isGroup prop. This will ensure that the correct aria attributes are being added in the right places.

const [value, setValue] = useState(""); return ( <FormElementWrapper label="Label" name="name" isGroup> {(formControlProps) => ( <> <InputField {...formControlProps} value={value} onChange={setValue} /> <Button onClick={() => console.log("clicked")}>Button</Button> </> )} </FormElementWrapper> );

#Single Select

Allows users to choose one option from a list.

Best Practices:

  • Use a clear label to describe the options in the list.
  • If there are only a few options, consider using Radios instead for improved visibility.
const items = [ { title: "Apple", value: 1 }, { title: "Banana", value: 2 }, { title: "Pear", value: 3 }, ]; const [selected, setSelected] = useState<number | undefined>(); return ( <FormElementWrapper label="Fruit" name="Fruit"> <Select items={items} value={selected} onChange={setSelected} noDefaultOption placeholder="Some placeholder" /> </FormElementWrapper> );

#Multi Select

Allows users to choose multiple options from a list.

Best Practices:

  • Follow the same guidelines as single select.
  • Clearly indicate how many options the user can select (e.g., "Select up to 3").
const items = [ { value: 0, title: "Apple" }, { value: 1, title: "Banana" }, { value: 2, title: "Blueberry" }, { value: 3, title: "Cherry" }, { value: 4, title: "Grape" }, { value: 5, title: "Guava" }, { value: 6, title: "Lemon" }, { value: 7, title: "Lime" }, { value: 8, title: "Orange" }, { value: 9, title: "Peach" }, { value: 10, title: "Pear" }, ]; const [selectedItems, setSelectedItems] = useState<number[]>([]); return ( <FormElementWrapper label="Fruit" name="Fruit"> <Select items={items} value={selectedItems} onChange={setSelectedItems} noDefaultOption bulkActions placeholder="Some placeholder" /> </FormElementWrapper> );

#Checkbox

Allows users to select multiple options from a set of checkboxes.

Best Practices:

  • Use a group label to explain the relationship between the checkboxes.
  • Ensure each checkbox has a clear and concise label.
const [selected, setSelected] = useState<string[]>([]); return ( <FormElementWrapper label="Fruit" name="Fruit"> <CheckboxGroup onChange={setSelected} value={selected}> <CheckboxGroup.Checkbox value="Apple">Apple</CheckboxGroup.Checkbox> <CheckboxGroup.Checkbox value="Banana">Banana</CheckboxGroup.Checkbox> <CheckboxGroup.Checkbox value="Pear">Pear</CheckboxGroup.Checkbox> </CheckboxGroup> </FormElementWrapper> );

#Radio button

Allows users to select a single option from a set of mutually exclusive choices.

Best Practices:

  • Use radio buttons for a limited number of options.
  • Ensure each radio button has a clear and concise label.
  • Group related radio buttons.
const [radioValue, setRadioValue] = useState("Apple"); return ( <FormElementWrapper label="Fruit" name="Fruit"> <Radios value={radioValue} onChange={setRadioValue}> <Radios.Radio value="Apple">Apple</Radios.Radio> <Radios.Radio value="Banana">Banana</Radios.Radio> <Radios.Radio value="Pear">Pear</Radios.Radio> </Radios> </FormElementWrapper> );

#Helptext

Provide additional context and immediate feedback to the user.

Best Practices:

  • Use concise help text to guide users.
  • Avoid excessive placeholder texts.

Below (default)

Helptext to understand the context of the form control better

Above

Helptext to understand the context of the form control better

const [value, setValue] = useState(""); const [value2, setValue2] = useState(""); return ( <> <H2>Below (default)</H2> <FormElementWrapper label="Label" name="name" helptext="Helptext to understand the context of the form control better" > <InputField value={value} onChange={setValue} /> </FormElementWrapper> <H2>Above</H2> <FormElementWrapper label="Label" name="name" helptext="Helptext to understand the context of the form control better" helptextPosition="above" > <InputField value={value2} onChange={setValue2} /> </FormElementWrapper> </> );

#Invalid state

Provide additional context and immediate feedback to the user.

Best Practices:

  • Validate input in real-time and provide clear error messages.
  • Use visual cues (color, icons) to indicate the state of the input (e.g error).

Some error message to let the user know what's wrong

const [value, setValue] = useState(""); const [value2, setValue2] = useState(""); return ( <> <FormElementWrapper label="Invalid state" name="name" invalid> <InputField value={value2} onChange={setValue2} /> </FormElementWrapper> <FormElementWrapper label="Invalid state with error" name="name" error="Some error message to let the user know what's wrong" invalid > <InputField value={value} onChange={setValue} /> </FormElementWrapper> </> );

#Helptext and invalid state

Provide additional context and immediate feedback to the user.

Best Practices:

  • Use concise help text to guide users.
  • Validate input in real-time and provide clear error messages.
  • Use visual cues (color and icons) to indicate the state of the input (e.g error).

Some error message to let the user know what's wrong

Helptext to understand the context of the form control better

const [value, setValue] = useState(""); return ( <> <FormElementWrapper label="Helptext and invalid state" name="name" helptext="Helptext to understand the context of the form control better" error="Some error message to let the user know what's wrong" invalid > <InputField value={value} onChange={setValue} /> </FormElementWrapper> </> );

#Horizontal

Arrange labels horizontally next to their corresponding input fields.

Best Practices:

  • Use for forms with limited space or shorter labels.
  • Ensure labels and inputs are visually aligned.
const [value, setValue] = useState(""); const [value2, setValue2] = useState(""); return ( <> <FormElementWrapper horizontal label="Label" name="name"> <InputField value={value} onChange={setValue} /> </FormElementWrapper> <FormElementWrapper horizontal label="Label with tooltip" tooltip="Some further explanation" name="name" > <InputField value={value2} onChange={setValue2} /> </FormElementWrapper> </> );

#Input with slugs, helptext and invalid state

Provide additional context and immediate feedback to the user.

Best Practices:

  • Use concise help text to guide users.
  • Validate input in real-time and provide clear error messages.
  • Use visual cues (color and icons) to indicate the state of the input (error).
Count:
items

Some error message to let the user know what's wrong

Helptext to understand the context of the form control better

const [value, setValue] = useState(""); return ( <> <FormElementWrapper label="Slugs, helptext and invalid state" name="name" helptext="Helptext to understand the context of the form control better" error="Some error message to let the user know what's wrong" invalid > <InputFieldWithSlug aria-label="My accessible input component" placeholder="Placeholder" name="some input" value={value} onChange={setValue} leftSlug="Count:" rightSlug="items" fullWidth /> </FormElementWrapper> </> );

#Tooltip variants

Provide additional information on hover or focus.

Best Practices:

  • Use tooltips sparingly for additional information that doesn't fit in the label.
  • Keep tooltip content brief and relevant.
const [value, setValue] = useState(""); return ( <> <FormElementWrapper label="Label with tooltip variant" name="name" tooltip={ <Tooltip variant={{ type: "icon-only" }} content="Some further explanation"> <Icon> <IconPotentialIssue /> </Icon> </Tooltip> } > <InputField value={value} onChange={setValue} /> </FormElementWrapper> </> );

#Properties

PropertyDescriptionDefinedValue
labelRequired
stringLabel for the form control
childrenRequired
| element | functionForm control
nameRequired
stringValue for the name attribute
tooltipOptional
| string | elementThe content of the form control tooltip
invalidOptional
booleanInvalid state of the form control
errorOptional
elementError message to be displayed when form control is in an invalid state
helptextOptional
elementHelptext to understand the context of the form control better
helptextPositionOptional
"above" | "below"Positions the helptext above or below the form control (defaults to "below")
horizontalOptional
booleanWhen true label and form control are displayed horizontally next to each other
isGroupOptional
booleanIf another component (e.g. a button) is used together with a regular form control as a group
classNameOptional
stringCustom className that's applied to the outermost element (only intended for special cases)
styleOptional
objectStyle object to apply custom inline styles (only intended for special cases)
data-observe-keyOptional
stringUnique string, used by external script e.g. for event tracking

#Guidelines

#Best practices

#General

Use FormElementWrapper when

  • Creating individual form elements (input fields, selects, checkboxes, radio buttons) within a larger form. See an Overview of form elements above.
  • You need to provide a consistent structure for labeling, help text, and error messages associated with each form element.

#Placement

FormElementWrapper is primarily used within Form to organize individual input fields. It can also be used within Modal or dialogs containing forms.

#Style

  • Siteimprove Design System: Adhere to Siteimprove's guidelines for color, typography, and spacing. If you are not using a component from Fancy, match the styling of your FormElementWrapper to existing components for visual consistency.
  • Alignment: Align the FormElementWrapper vertically with other form elements on the page, adhering to the Grid and Grid.Section layout defined by your design system.
  • Optional vs. Mandatory:
    • Clearly indicate required fields with "(required)" or an asterisk (*).
    • If most fields are optional, only mark required fields. If most are required, mark optional fields.

#Do not use when

  • The form element does not require a label, help text, or error message display.

#Accessibility

#For designers

  • Ensure that all elements within the FormElementWrapper (labels, inputs, help text, error messages) have sufficient color contrast and are easily distinguishable.
  • If errors are present after form submission, automatically move focus to the first error message.

#For developers

  • Ensure that all input fields have associated labels that are visible and programmatically linked.

Explore detailed guidelines for this component: Accessibility Specifications

#Writing

  • Write clear and concise labels (1-3 words) that accurately describe the expected input.
  • Use sentence case (capitalize the first word only).
  • Avoid punctuation at the end of labels.
  • Omit unnecessary words like "the", "a", or "an".
  • Prioritize descriptive labels over instructional ones (e.g., "Email address" instead of "Enter your email address").