Skip to Content

Form Field

Form Field allows users to wrap input components to make them accessible and adds complementary labels and error messages.

Interaction Modes

Customizing

Reviewing

Install

yarn add @workday/canvas-kit-react

Component Type

Input

Platform

Web

Component

Sana Canvas

Delivery Channels

Web

Version

16.1.7

Experience Surfaces

Page Body Inline

Component Type

Input

Platform

Web

Component

Sana Canvas

Delivery Channels

Web

Version

16.1.7

Experience Surfaces

Page Body Inline

Usage Guidance

The Form Field is a wrapper component intended to be used with Canvas Kit input components when designing a form to ensure they meet accessibility standards. Inputs collect data from users within a form. It’s important to choose the right input to elicit a response in the format you want. For more information on best practices for designing forms, reference the Form  pattern.

When to Use

  • Use the Form Field component as a wrapper for most inputs on a form. From a designer perspective, it is not a visible component but something to be aware of when working with developers on a form as the Canvas Kit Form Field should encapsulate input components on a form.
  • Use form fields to ensure forms meet accessibility guidelines.

When to Use Something Else

  • Consider using a Table when presenting and editing sets of repeating data with the same structure.
  • Consider using a Popup or Toast component to display confirmation messages or validate user inputs in the context of a user action.

Examples

Basic

Form Field should be used in tandem with most Canvas Kit input components to ensure they meet accessibility standards. The orientation of the label by default is vertical.

import React from 'react';

import {FormField} from '@workday/canvas-kit-react/form-field';
import {Flex} from '@workday/canvas-kit-react/layout';
import {TextInput} from '@workday/canvas-kit-react/text-input';

export default () => {
  const [value, setValue] = React.useState('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  return (
    <Flex>
      <FormField>
        <FormField.Label>First Name</FormField.Label>
        <FormField.Field>
          <FormField.Input as={TextInput} value={value} onChange={handleChange} />
        </FormField.Field>
      </FormField>
    </Flex>
  );
};

Error States

Set the error prop of the Form Field or define it in the model to indicate it has an error. error accepts the following values:

"error" | "caution" | undefined

Caution

Use the caution state when a value is valid but there is additional information.

Alert: Password strength is weak, using more characters is recommended.

import React from 'react';

import {FormField} from '@workday/canvas-kit-react/form-field';
import {Flex} from '@workday/canvas-kit-react/layout';
import {TextInput} from '@workday/canvas-kit-react/text-input';

export default () => {
  const [value, setValue] = React.useState('hi');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  return (
    <Flex>
      <FormField error="caution">
        <FormField.Label>Create Password</FormField.Label>
        <FormField.Field>
          <FormField.Input as={TextInput} type="password" value={value} onChange={handleChange} />
          <FormField.Hint>
            Alert: Password strength is weak, using more characters is recommended.
          </FormField.Hint>
        </FormField.Field>
      </FormField>
    </Flex>
  );
};

Accessibility Note: Caution state will not include the aria-invalid attribute on the input for screen readers. Use error states when values are not valid.

Error

Use the error state when the value is no longer valid.

Error: Must Contain a number and a capital letter

import React from 'react';

import {FormField} from '@workday/canvas-kit-react/form-field';
import {Flex} from '@workday/canvas-kit-react/layout';
import {TextInput} from '@workday/canvas-kit-react/text-input';

export default () => {
  const [value, setValue] = React.useState('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  return (
    <Flex>
      <FormField error="error">
        <FormField.Label>Password</FormField.Label>
        <FormField.Field>
          <FormField.Input as={TextInput} type="password" value={value} onChange={handleChange} />
          <FormField.Hint>Error: Must Contain a number and a capital letter</FormField.Hint>
        </FormField.Field>
      </FormField>
    </Flex>
  );
};

Accessibility Note: Error states include visual color changes to the input border and require supplemental “error” text for colorblind users to distinguish between fields in an error state from fields with standard hint text. Read more about Failure of Success Criterion 1.4.1 due to identifying required or error fields using color differences only 

Hint

Use FormField.Hint to display a short message below the input component and FormField.Field to ensure proper alignment.

Cannot contain numbers

import React from 'react';

import {FormField} from '@workday/canvas-kit-react/form-field';
import {Flex} from '@workday/canvas-kit-react/layout';
import {TextInput} from '@workday/canvas-kit-react/text-input';

export default () => {
  const [value, setValue] = React.useState('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  return (
    <Flex>
      <FormField orientation="horizontalStart">
        <FormField.Label>First Name</FormField.Label>
        <FormField.Field>
          <FormField.Input as={TextInput} value={value} onChange={handleChange} />
          <FormField.Hint>Cannot contain numbers</FormField.Hint>
        </FormField.Field>
      </FormField>
    </Flex>
  );
};

Accessibility Note: Hints are automatically associated to the input field with the aria-describedby attribute. This ensures that screen readers can automatically announce the hint text to users when the input field is focused.

Disabled

Set the disabled prop of FormField.Input to prevent users from interacting with it.

import React from 'react';

import {FormField} from '@workday/canvas-kit-react/form-field';
import {Flex} from '@workday/canvas-kit-react/layout';
import {TextInput} from '@workday/canvas-kit-react/text-input';

export default () => {
  const [value, setValue] = React.useState('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  return (
    <Flex>
      <FormField>
        <FormField.Label>Email</FormField.Label>
        <FormField.Field>
          <FormField.Input as={TextInput} value={value} disabled onChange={handleChange} />
        </FormField.Field>
      </FormField>
    </Flex>
  );
};

Accessibility Note: Disabled form elements are exempt from WCAG minimum contrast guidelines . Despite this exemption, disabled fields are more difficult for low vision and colorblind users to perceive and may harm the usability of the form. Consider using text elements instead, or read-only fields if users cannot modify data.

Label Position

Set the orientation prop of the Form Field to designate the position of the label relative to the input component. By default, the orientation will be set to vertical. If you want your label to be horizontal, you have two options: horizontalStart and horizontalEnd.

If you want the position of the label at the start of the container, set orientation prop to horizontalStart.

import React from 'react';

import {FormField} from '@workday/canvas-kit-react/form-field';
import {TextInput} from '@workday/canvas-kit-react/text-input';
import {createStyles} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';

const formStyles = createStyles({
  display: 'flex',
  gap: system.gap.sm,
  flexDirection: 'column',
});

export default () => {
  const [value, setValue] = React.useState('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  return (
    <form className={formStyles}>
      <FormField orientation="horizontalStart">
        <FormField.Label>Email</FormField.Label>
        <FormField.Input as={TextInput} value={value} onChange={handleChange} />
      </FormField>
      <FormField orientation="horizontalStart">
        <FormField.Label>Password</FormField.Label>
        <FormField.Input as={TextInput} type="password" />
      </FormField>
    </form>
  );
};

If you want the position of the label at the end of the container, set orientation prop to horizontalEnd.

import React from 'react';

import {FormField} from '@workday/canvas-kit-react/form-field';
import {TextInput} from '@workday/canvas-kit-react/text-input';
import {createStyles} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';

const formStyles = createStyles({
  display: 'flex',
  gap: system.gap.sm,
  flexDirection: 'column',
});

export default () => {
  const [value, setValue] = React.useState('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  return (
    <form className={formStyles}>
      <FormField orientation="horizontalEnd">
        <FormField.Label>Email</FormField.Label>
        <FormField.Input as={TextInput} value={value} onChange={handleChange} />
      </FormField>
      <FormField orientation="horizontalEnd">
        <FormField.Label>Password</FormField.Label>
        <FormField.Input as={TextInput} type="password" />
      </FormField>
    </form>
  );
};

Grow

Set the grow prop of the Form Field to true to configure it (including the wrapped input component) to expand to the width of its container.

Note: This Prop is deprecated and will be removed in a future major version.

import React from 'react';

import {FormField} from '@workday/canvas-kit-react/form-field';
import {Flex} from '@workday/canvas-kit-react/layout';
import {TextInput} from '@workday/canvas-kit-react/text-input';

export default () => {
  const [value, setValue] = React.useState('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  return (
    <Flex>
      <FormField grow>
        <FormField.Label>First Name</FormField.Label>
        <FormField.Input as={TextInput} value={value} onChange={handleChange} />
      </FormField>
    </Flex>
  );
};

Ref Forwarding

If you need full customization you can use the FormField behavior hooks to build your own solution. It is also easy it work with custom components or third party libraries and get the CKR accessibility guarantees by using the as prop.

import React from 'react';

import {SecondaryButton} from '@workday/canvas-kit-react/button';
import {changeFocus} from '@workday/canvas-kit-react/common';
import {FormField} from '@workday/canvas-kit-react/form-field';
import {Flex} from '@workday/canvas-kit-react/layout';
import {TextInput} from '@workday/canvas-kit-react/text-input';
import {createStyles} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';

const parentContainerStyles = createStyles({
  gap: system.gap.xs,
  alignItems: 'flex-start',
  flexDirection: 'column',
});

export default () => {
  const [value, setValue] = React.useState('');
  const ref = React.useRef(null);

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  const handleClick = () => {
    changeFocus(ref.current);
  };

  return (
    <Flex cs={parentContainerStyles}>
      <FormField>
        <FormField.Label>Email</FormField.Label>
        <FormField.Field>
          <FormField.Input as={TextInput} onChange={handleChange} value={value} ref={ref} />
        </FormField.Field>
      </FormField>
      <SecondaryButton onClick={handleClick}>Focus Text Input</SecondaryButton>
    </Flex>
  );
};

Required

Set the isRequired prop of the Form Field to true to indicate that the field is required. Labels for required fields are suffixed by a red asterisk.

import React from 'react';

import {FormField} from '@workday/canvas-kit-react/form-field';
import {TextInput} from '@workday/canvas-kit-react/text-input';

export default () => {
  const [value, setValue] = React.useState('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  return (
    <FormField isRequired={true}>
      <FormField.Label>Email</FormField.Label>
      <FormField.Field>
        <FormField.Input
          as={TextInput}
          placeholder="your@gmail.com"
          onChange={handleChange}
          value={value}
        />
      </FormField.Field>
    </FormField>
  );
};

Accessibility Note: The HTML required attribute will be added to the input field and announced by screen readers. Consider adding a note at the top of your form indicating that fields marked with an asterisk (*) are required. This provides context for all users.

Grouped Inputs

Use FormFieldGroup when you have a group of inputs that need to be associated to one another, like RadioGroup or a group of Checkbox’s. FormFieldGroup renders a div with role="group" and an aria-labelledby reference. FormFieldGroup.Label renders a div with an id referenced by the aria-labelledby of the FormFieldGroup. Screen readers announce the group label when focusing controls in the group.

FormFieldGroup supports the same props of FormField:

  • error: "caution" | "error" Defines the error around the whole group of inputs.
  • orientation: "vertical" | "horizontalStart" | "horizontalEnd" Defines the group label placement.
  • isRequired: true Defines if a group like RadioGroup is required.

Choose your pizza options

Choose Your Toppings
Choose Your Crust
Selected Toppings:
Selected Crust:
import React from 'react';

import {RadioGroup} from '@workday/canvas-kit-preview-react/radio';
import {Banner} from '@workday/canvas-kit-react/banner';
import {PrimaryButton, SecondaryButton} from '@workday/canvas-kit-react/button';
import {Checkbox} from '@workday/canvas-kit-react/checkbox';
import {AriaLiveRegion} from '@workday/canvas-kit-react/common';
import {FormFieldGroup} from '@workday/canvas-kit-react/form-field';
import {createStyles, px2rem} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';

const formStyles = createStyles({
  margin: `0 ${px2rem(12)}`,
});

const formButtonStyles = createStyles({
  display: 'inline-flex',
  gap: system.gap.sm,
});

const toppings = [
  {
    id: 1,
    label: 'Pepperoni',
    checked: false,
  },
  {
    id: 2,
    label: 'Cheese',
    checked: false,
  },
  {
    id: 3,
    label: 'Pineapple',
    checked: false,
  },
  {
    id: 4,
    label: 'Mushrooms',
    checked: false,
  },
];

const bannerStyles = createStyles({
  position: 'absolute',
  right: 0,
});

export default () => {
  const [toppingsState, setToppingsState] = React.useState(toppings);
  const [error, setError] = React.useState(undefined);
  const [radioError, setRadioError] = React.useState(undefined);
  const [showSuccess, setShowSuccess] = React.useState(false);

  const [value, setValue] = React.useState<string>('');
  const [formData, setFormData] = React.useState({
    toppings: [],
    crust: '',
  });
  const handleCheckboxCheck = id => {
    if (error) {
      setError(undefined);
    }
    setToppingsState(
      toppingsState.map(item => (item.id === id ? {...item, checked: !item.checked} : item))
    );
  };

  const handleRadioChange = (e: React.ChangeEvent) => {
    if (radioError) {
      setRadioError(undefined);
    }
    const target = e.currentTarget;
    if (target instanceof HTMLInputElement) {
      setValue(target.value);
    }
  };

  const handleSubmit = e => {
    e.preventDefault();
    const radioError = !value && toppingsState.some(item => !item.checked) ? 'error' : undefined;
    const error = toppingsState.every(item => !item.checked) ? 'error' : undefined;

    setRadioError(radioError);
    setError(error);
    if (!error && !radioError && toppingsState.some(item => item.checked) && value) {
      setShowSuccess(true);
    }
    setFormData({
      toppings: toppingsState,
      crust: value,
    });
  };

  React.useEffect(() => {
    const timeout = setTimeout(() => {
      if (showSuccess) {
        setShowSuccess(false);
      }
    }, 3000);

    return () => clearTimeout(timeout);
  }, [showSuccess]);

  const handleReset = () => {
    setFormData({toppings: [], crust: ''});
    setError(undefined);
    setValue('');
    setRadioError('');
    setShowSuccess(false);
    setToppingsState(
      toppingsState.map(item => {
        return {...item, checked: false};
      })
    );
  };

  return (
    <div>
      <h3>Choose your pizza options</h3>
      <AriaLiveRegion role="alert">
        <div style={{display: 'flex', gap: '40px'}}>
          {error || radioError ? (
            <Banner isSticky hasError className={bannerStyles}>
              <Banner.Label>
                {error && radioError
                  ? 'At least one topping and crust selection is required'
                  : error
                    ? 'You must choose at least one topping'
                    : radioError
                      ? 'You must choose a crust'
                      : ''}
              </Banner.Label>
            </Banner>
          ) : null}
          {showSuccess && (
            <Banner isSticky className={bannerStyles}>
              <Banner.Label>You've successfully submitted your pizza options.</Banner.Label>
            </Banner>
          )}
        </div>
      </AriaLiveRegion>

      <form className={formStyles} onSubmit={handleSubmit}>
        <FormFieldGroup error={error} isRequired>
          <FormFieldGroup.Label>Choose Your Toppings</FormFieldGroup.Label>
          <FormFieldGroup.List>
            {toppingsState.map(item => {
              return (
                <FormFieldGroup.Input
                  key={item.id}
                  onChange={() => handleCheckboxCheck(item.id)}
                  checked={item.checked}
                  value={item.label}
                  as={Checkbox}
                  disabled={item.label === 'Pineapple' ? true : undefined}
                  label={item.label}
                />
              );
            })}
          </FormFieldGroup.List>
          <FormFieldGroup.Hint>
            {error === 'error' && 'Error: You must choose one topping'}
          </FormFieldGroup.Hint>
        </FormFieldGroup>
        <FormFieldGroup error={radioError} isRequired>
          <FormFieldGroup.Label>Choose Your Crust</FormFieldGroup.Label>
          <FormFieldGroup.Field>
            <FormFieldGroup.List
              as={RadioGroup}
              onChange={handleRadioChange}
              value={value}
              name="crust"
            >
              <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin-crust">
                Thin Crust
              </FormFieldGroup.Input>
              <FormFieldGroup.Input as={RadioGroup.RadioButton} value="hand-tossed">
                Hand Tossed
              </FormFieldGroup.Input>
              <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">
                Deep Dish
              </FormFieldGroup.Input>
              <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">
                Cauliflower
              </FormFieldGroup.Input>
            </FormFieldGroup.List>
            <FormFieldGroup.Hint>
              {radioError === 'error' ? 'Error: You must choose a crust' : null}
            </FormFieldGroup.Hint>
          </FormFieldGroup.Field>
        </FormFieldGroup>
        <div className={formButtonStyles}>
          <PrimaryButton type="submit">Submit Your Choices</PrimaryButton>
          <SecondaryButton onClick={() => handleReset()}>Reset Form</SecondaryButton>
        </div>
      </form>
      <div>
        <div>
          Selected Toppings:{' '}
          {!error && formData.toppings.map(item => (item.checked ? `${item.label} ` : null))}
        </div>
        <div>Selected Crust: {formData.crust}</div>
      </div>
    </div>
  );
};

Accessibility Note: In addition to radio button and checkbox groups, FormFieldGroup can be useful in any situation where the form needs to have multiple sets of identical input fields. For example, a form with identical fields for a Shipping address and a Billing address. The legend (group label) provides critical context for screen reader users in these situations.

Custom

If you need full customization you can use the FormField behavior hooks to build your own solution. It is also easy it work with custom components or third party libraries and get the CKR accessibility guarantees by using the as prop.

You can be anything
import React from 'react';

import {useModelContext} from '@workday/canvas-kit-react/common';
import {
  formFieldStencil,
  useFormFieldHint,
  useFormFieldInput,
  useFormFieldLabel,
  useFormFieldModel,
} from '@workday/canvas-kit-react/form-field';
import {Flex} from '@workday/canvas-kit-react/layout';

const Label = ({model, children}) => {
  const localModel = useModelContext(useFormFieldModel.Context, model);
  const props = useFormFieldLabel(localModel);

  return (
    <label {...props}>
      {children}
      {model.state.isRequired ? '*' : ''}
    </label>
  );
};

const Hint = ({model, children}) => {
  const localModel = useModelContext(useFormFieldModel.Context, model);
  const props = useFormFieldHint(localModel);

  return <span {...props}>{children}</span>;
};

const Input = ({model, ...elementProps}) => {
  const localModel = useModelContext(useFormFieldModel.Context, model);
  const props = useFormFieldInput(localModel, elementProps);

  return <input type="text" required={model.state.isRequired ? true : false} {...props} />;
};

export default () => {
  const [value, setValue] = React.useState('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  const model = useFormFieldModel({isRequired: true});

  return (
    <Flex cs={formFieldStencil({orientation: 'horizontalStart'})}>
      <Label model={model}>My Custom Field</Label>
      <Input model={model} value={value} onChange={handleChange} />
      <Hint model={model}>You can be anything</Hint>
    </Flex>
  );
};

Custom id

Form Field will automatically generate an HTML id for its input element to link it to the correponding label. Alternatively, you may set the id prop of the Form Field to specify a custom id for the input element. The id will be appended by input-${your-unique-id}.

import React from 'react';

import {FormField} from '@workday/canvas-kit-react/form-field';
import {Flex} from '@workday/canvas-kit-react/layout';
import {TextInput} from '@workday/canvas-kit-react/text-input';

export default () => {
  const [value, setValue] = React.useState('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  return (
    <Flex>
      <FormField id="first-name">
        <FormField.Label>First Name</FormField.Label>
        <FormField.Field>
          <FormField.Input as={TextInput} value={value} onChange={handleChange} />
        </FormField.Field>
      </FormField>
    </Flex>
  );
};

All Fields

Form Field should allow you to use it with all inputs including Select, TextInput, Checkbox, TextArea, Switch, and RadioGroup.

Hint text for your input

Radio Group Legend

Error Message

Checkbox Legend
Choose Your Crust
Checkbox Legend
import {RadioGroup} from '@workday/canvas-kit-preview-react/radio';
import {Checkbox} from '@workday/canvas-kit-react/checkbox';
import {FormField, FormFieldGroup} from '@workday/canvas-kit-react/form-field';
import {Flex} from '@workday/canvas-kit-react/layout';
import {Select} from '@workday/canvas-kit-react/select';
import {Switch} from '@workday/canvas-kit-react/switch';
import {TextArea} from '@workday/canvas-kit-react/text-area';
import {TextInput} from '@workday/canvas-kit-react/text-input';
import {calc, createStyles} from '@workday/canvas-kit-styling';
import {base, system} from '@workday/canvas-tokens-web';

const parentContainerStyles = createStyles({
  flexDirection: 'column',
  gap: calc.subtract(system.gap.lg, system.gap.xs),
  padding: calc.subtract(base.size500, system.padding.xxs),
  borderRadius: system.shape.sm,
});

export default () => {
  return (
    <Flex cs={parentContainerStyles}>
      <FormField grow>
        <FormField.Label>First Name</FormField.Label>
        <FormField.Field>
          <FormField.Input as={TextInput} />
        </FormField.Field>
      </FormField>

      <FormField isRequired={true} error="caution" grow>
        <FormField.Label>Email</FormField.Label>
        <FormField.Field>
          <FormField.Input as={TextInput} />
          <FormField.Hint>Hint text for your input</FormField.Hint>
        </FormField.Field>
      </FormField>
      <FormField grow>
        <FormField.Label>Text Area Label</FormField.Label>
        <FormField.Field>
          <FormField.Input as={TextArea} />
        </FormField.Field>
      </FormField>
      <FormField error="error" grow>
        <FormField.Label>Choose a Crust</FormField.Label>
        <Select items={['Pizza', 'Cheeseburger', 'Fries']}>
          <FormField.Input as={Select.Input} />
          <Select.Popper>
            <Select.Card>
              <Select.List>{item => <Select.Item>{item}</Select.Item>}</Select.List>
            </Select.Card>
          </Select.Popper>
        </Select>
      </FormField>
      <FormField as="fieldset" isRequired={true} error={'error'} orientation="horizontalStart" grow>
        <FormField.Label as="legend">Radio Group Legend</FormField.Label>
        <FormField.Field>
          <FormField.Input as={RadioGroup}>
            <RadioGroup.RadioButton value="deep-dish">Deep dish</RadioGroup.RadioButton>
            <RadioGroup.RadioButton value="thin">Thin</RadioGroup.RadioButton>
            <RadioGroup.RadioButton value="gluten-free">Gluten free</RadioGroup.RadioButton>
            <RadioGroup.RadioButton value="cauliflower">Cauliflower</RadioGroup.RadioButton>
            <RadioGroup.RadioButton value="butter">
              Butter - the best thing to put on bread
            </RadioGroup.RadioButton>
          </FormField.Input>
          <FormField.Hint>Error Message</FormField.Hint>
        </FormField.Field>
      </FormField>
      <FormField as="fieldset" grow>
        <FormField.Label as="legend">Checkbox Legend</FormField.Label>
        <FormField.Input checked={true} as={Checkbox} label="Checkbox Label" />
        <FormField.Input checked={false} as={Checkbox} label="Thin Crust" />
        <FormField.Input checked={false} as={Checkbox} label="Extra Cheese" />
      </FormField>
      <FormFieldGroup error="error" orientation="horizontalStart" grow>
        <FormFieldGroup.Label>Choose Your Crust</FormFieldGroup.Label>
        <FormFieldGroup.Field>
          <FormFieldGroup.List as={RadioGroup}>
            <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin-crust">
              Thin Crust
            </FormFieldGroup.Input>
            <FormFieldGroup.Input as={RadioGroup.RadioButton} value="hand-tossed">
              Hand Tossed
            </FormFieldGroup.Input>
            <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">
              Deep Dish
            </FormFieldGroup.Input>
            <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">
              Cauliflower
            </FormFieldGroup.Input>
          </FormFieldGroup.List>
        </FormFieldGroup.Field>
      </FormFieldGroup>
      <FormFieldGroup grow>
        <FormFieldGroup.Label>Checkbox Legend</FormFieldGroup.Label>
        <FormField.Field>
          <FormFieldGroup.List>
            <FormFieldGroup.Input checked={true} as={Checkbox} label="Checkbox Label" />
            <FormFieldGroup.Input checked={false} as={Checkbox} label="Thin Crust" />
            <FormFieldGroup.Input checked={false} as={Checkbox} label="Extra Cheese" />
          </FormFieldGroup.List>
        </FormField.Field>
      </FormFieldGroup>

      <FormField orientation="horizontalStart" grow>
        <FormField.Label>Switch Label</FormField.Label>
        <FormField.Field>
          <FormField.Input as={Switch} />
        </FormField.Field>
      </FormField>
    </Flex>
  );
};

Hidden Label

In cases where you want to hide the label while still meeting accessibility standards, you can add isHidden on the <FormField.Label/>. This prop will visually hide the label.

import React from 'react';

import {
  FormField,
  useFormFieldInput,
  useFormFieldModel,
} from '@workday/canvas-kit-react/form-field';
import {SystemIcon} from '@workday/canvas-kit-react/icon';
import {Flex} from '@workday/canvas-kit-react/layout';
import {InputGroup, TextInput} from '@workday/canvas-kit-react/text-input';
import {searchIcon} from '@workday/canvas-system-icons-web';

/**
 * Using `as={InputGroup}` on `FormField.Input` will break the label associations necessary for accessibility.
 * In this example, we've rendered `FormField.Field` as `InputGroup` and then hoisted the `id` of the input from the FormField model.
 * This allows us to set the `id` of the `InputGroup.Input` correctly for proper label association.
 */

export default () => {
  const [value, setValue] = React.useState('');
  const model = useFormFieldModel();
  const {id: formFieldInputId} = useFormFieldInput(model);

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  return (
    <Flex>
      <FormField model={model}>
        <FormField.Label isHidden>Search</FormField.Label>
        <FormField.Field as={InputGroup}>
          <InputGroup.InnerStart>
            <SystemIcon icon={searchIcon} size="small" />
          </InputGroup.InnerStart>
          <InputGroup.Input
            as={TextInput}
            id={formFieldInputId}
            onChange={handleChange}
            value={value}
          />
        </FormField.Field>
      </FormField>
    </Flex>
  );
};

Accessibility Note: Hidden labels are typically not recommended. In this example, a universally recognizable icon like a magnifying glass signaling “search” may be a suitable alternative to visible text labels.

Themed Errors

You can theme your error rings by wrapping an input in a CanvasProvider and defining focusOutline and error properties on the theme.

Please enter an email.

import React from 'react';

import {CanvasProvider, PartialEmotionCanvasTheme} from '@workday/canvas-kit-react/common';
import {FormField} from '@workday/canvas-kit-react/form-field';
import {TextInput} from '@workday/canvas-kit-react/text-input';
import {createStyles, cssVar} from '@workday/canvas-kit-styling';
import {base, system} from '@workday/canvas-tokens-web';

const formFieldHintStyles = createStyles({
  paddingBlockStart: system.padding.xs,
});

export default () => {
  const [value, setValue] = React.useState('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  const theme: PartialEmotionCanvasTheme = {
    canvas: {
      palette: {
        common: {
          focusOutline: cssVar(base.green600),
        },
        error: {
          main: cssVar(base.magenta700),
        },
      },
    },
  };

  return (
    <CanvasProvider theme={theme}>
      <FormField error={!value ? 'error' : undefined} isRequired={true} orientation="vertical">
        <FormField.Label>Email</FormField.Label>
        <FormField.Field>
          <FormField.Input as={TextInput} onChange={handleChange} value={value} />
          <FormField.Hint cs={formFieldHintStyles}>
            {!value && 'Please enter an email.'}
          </FormField.Hint>
        </FormField.Field>
      </FormField>
    </CanvasProvider>
  );
};

Custom Styles

Form Field and its subcomponents support custom styling via the cs prop. For more information, check our “How To Customize Styles” .

Accessibility

FormField provides essential accessibility features to ensure form inputs have a programmatically determinable name, relationships, and instructions. The primary accessibility goal is to ensure assistive technology users can identify every field, understand how to complete it, and hear hints, errors, and required state when the form input receives focus.

Minimum Accessible Structure

import {FormField} from '@workday/canvas-kit-react/form-field'; import {TextInput} from '@workday/canvas-kit-react/text-input'; <FormField> <FormField.Label>Email</FormField.Label> <FormField.Field> <FormField.Input as={TextInput} /> <FormField.Hint>We'll never share your email.</FormField.Hint> </FormField.Field> </FormField>;

Include FormField.Hint whenever there is hint or error text—the wiring slot for aria-describedby exists by default (see Built-in Behaviors).

Built-in Behaviors

Canvas Kit applies these automatically when you compose FormField with its subcomponents. Do not duplicate them in consuming code.

ARIA and DOM (applied by subcomponents):

  • FormField.Label: <label> with htmlFor matching the id on FormField.Input (input-{id}). Clicking the label moves focus to the input.
  • FormField.Input: id (input-{id}), aria-labelledby (label-{id}), aria-describedby (hint-{id} when an id exists), required when isRequired, and aria-invalid="true" when error="error". Caution (error="caution") does not set aria-invalid.
  • FormField.Hint: id="hint-{id}" for description association.
  • Generated IDs: label-{id}, input-{id}, and hint-{id} from the FormField id (auto-generated or custom via the id prop).
  • FormFieldGroup: role="group" with aria-labelledby referencing FormFieldGroup.Label.
  • Composite controls (for example, MultiSelect) forward aria-labelledby to related sub-elements (combobox, listbox) so every part shares the same accessible name.

Implementation note on aria-describedby: FormField.Input always sets aria-describedby="hint-{id}" when an id exists, even if FormField.Hint is not rendered. Always render FormField.Hint when there is hint or error text. Omitting FormField.Hint leaves a dangling aria-describedby reference.

Keyboard (standard form control behavior):

  • Tab / Shift+Tab move focus to and from the input (native tab order)
  • Clicking FormField.Label moves focus to the associated input (native <label> behavior)
  • Checkbox, radio, and composite controls follow the wrapped input component’s own keyboard patterns

Screen reader expectations (when built-in behaviors are used as intended):

  • On focus, assistive technology announces the field label and, when applicable: required state, invalid state (error="error"), and hint or error text via aria-describedby
  • The Caution state is visual only —aria-invalid is not set for error="caution"
  • In a FormFieldGroup, the group label is associated via aria-labelledby; focusing a control in the group includes the group name in context
  • Disabled inputs are skipped in the tab order and may be announced as unavailable

For a simple field, the DOM looks like:

<div> <label id="label-abc" for="input-abc">First Name</label> <input id="input-abc" aria-labelledby="label-abc" /> </div>

Some composite controls such as MultiSelect, have additional sub-elements that also need to be linked to the FormField.Label. In the example below, the FormField.Label is applied to both the input[role=combobox] element and the ul[role=listbox] element so that screen reader knows that the label for both is the “States you’ve lived in”.

<div> <label id="label-abc" for="input-abc">States you've lived in</label> <input id="input-abc" aria-labelledby="label-abc" role="combobox" aria-expanded="false" aria-autocomplete="list" aria-controls="listbox-abc" type="text" /> <ul id="listbox-abc" role="listbox" aria-labelledby="label-abc"> <li role="option">Texas</li> <li role="option">California</li> </ul> </div>

For a field in an error state, the error text is referenced using aria-describedby. The rendered markup looks like:

<div> <label id="label-abc" for="input-abc">Password</label> <input id="input-abc" aria-labelledby="label-abc" aria-describedby="hint-abc" required aria-invalid="true" /> <p id="hint-abc">Error: Must contain a number and a capital letter</p> </div>

For grouped checkbox controls, compose a FormFieldGroup with FormFieldGroup.Label and FormFieldGroup.Input. The rendered markup looks like:

<div role="group" aria-labelledby="label-abc"> <div id="label-abc">Pizza toppings:</div> <div> <input type="checkbox" id="checkbox-1" /> <label for="checkbox-1">Pepperoni</label> </div> <div> <input type="checkbox" id="checkbox-2" /> <label for="checkbox-2">Mushrooms</label> </div> <div> <input type="checkbox" id="checkbox-3" /> <label for="checkbox-3">Pineapple</label> </div> </div>

Accessibility Requirements

Required in application code for accessible form fields. Rows marked (conditional) apply only when the situation matches—otherwise omit.

If no design spec is provided: use a visible FormField.Label, wrap the input with FormField.Input, omit isHidden, and omit a custom id unless testing or composition requires it.

RequirementHow to satisfy
Visible labelFormField.Label with concise, meaningful text
Input wiringFormField.Input as={...} wrapping every Canvas Kit input (TextInput, Select, TextArea, etc.)
Hint or error text (conditional)FormField.Hint when there is help or validation copy—required because aria-describedby is wired by default (see Built-in Behaviors)
Error state (conditional)error="error" on FormField and FormField.Hint prefixed with “Error:” so users who cannot perceive color can distinguish errors from hints
Caution state (conditional)error="caution" on FormField with descriptive FormField.Hint (no aria-invalid)
Required field (conditional)isRequired on FormField; consider a form-level note that asterisk (*) marks required fields
Group label (conditional)FormFieldGroup + FormFieldGroup.Label for radio buttons, checkbox groups, or related inputs. Alternatively, FormField as="fieldset" with FormField.Label as="legend"
Hidden label (conditional)FormField.Label isHidden only when an equally clear alternative exists (for example, a universally recognizable search icon)
Stable IDs (conditional)id prop on FormField when multiple fields share a page or predictable label-, input-, and hint- IDs are needed for testing or custom composition

Summary for code generation:

  • REQUIRED: visible label, input wiring
  • CONDITIONAL: hint/error text, required state, group label, hidden label, stable id

Anti-Patterns

Do not generate code that does the following (see Accessibility Requirements above for what to supply instead):

  • Manually set id, htmlFor, aria-labelledby, aria-describedby, aria-invalid, or required on FormField.Input or FormField.Label — Canvas Kit subcomponents wire these automatically
  • Unlabeled inputs: Do not use Canvas Kit inputs without FormField and FormField.Label.
  • Placeholder-only labels: Do not rely on placeholder instead of FormField.Label; placeholders disappear while typing and are poor substitutes for labels.
  • Color-only errors: Do not set error="error" without descriptive text in FormField.Hint.
  • Caution for invalid values: Do not use error="caution" when a value is invalid; use error="error" so aria-invalid is exposed.
  • Broken ID references: Do not point aria-labelledby or aria-describedby at missing or empty elements; ensure FormField.Label and FormField.Hint render meaningful content.
  • Skipping group labels: Do not render RadioGroup or multiple related checkboxes without FormFieldGroup and FormFieldGroup.Label (or FormField with as="fieldset" and FormField.Label as="legend").
  • Disabled when read-only fits: Avoid disabled on FormField.Input when users only need to view data; disabled fields are harder to perceive and are removed from the tab order.

Component API

FormField

Use FormField to wrap input components to make them accessible. You can customize the field by passing in TextInput, Select, RadioGroup and other form elements to FormField.Input through the as prop.

<FormField> <FormField.Label>First Name</FormField.Label> <FormField.Input as={TextInput} value={value} onChange={(e) => console.log(e)} /> </FormField>

Layout Component

FormField supports all props from thelayout component.

Props

Props extend from div. Changing the as prop will change the element interface.

Props extend from . If a model is passed, props from FormFieldModelConfig are ignored.

NameTypeDescriptionDefault
orientation 'vertical' | 'horizontalStart' | 'horizontalEnd'

The direction the child elements should stack. In v13, horizontal will be removed. Please use horizontalStart or horizontalEnd for horizontal alignment.

'vertical'
childrenReactNode
cs

The cs prop takes in a single value or an array of values. You can pass the CSS class name returned by , or the result of and . If you're extending a component already using cs, you can merge that prop in as well. Any style that is passed to the cs prop will override style props. If you wish to have styles that are overridden by the css prop, or styles added via the styled API, use wherever elemProps is used. If your component needs to also handle style props, use instead.

import {handleCsProp} from '@workday/canvas-kit-styling'; import {mergeStyles} from '@workday/canvas-kit-react/layout'; // ... // `handleCsProp` handles compat mode with Emotion's runtime APIs. `mergeStyles` has the same // function signature, but adds support for style props. return ( <Element {...handleCsProp(elemProps, [ myStyles, myModifiers({ size: 'medium' }), myVars({ backgroundColor: 'red' }) ])} > {children} </Element> )
growboolean

True if the component should grow to its container's width. False otherwise.

asReact.ElementType

Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using React.forwardRefand spread extra props to a root element.

Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care.

div
refReact.Ref<R = div>

Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If as is set to an element, it will be that element. If as is a component, the reference will be to that component (or element if the component uses React.forwardRef).

model

Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context.

elemPropsHook(
  model: ,
  elemProps: TProps
) => HTML Attributes

Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one.

FormField.Input

FormField.Input will render any inputs passed to it via the as prop, including TextInput, Select, Switch, TextArea, RadioGroup or any custom input. FromField.Input will be associated with FormField.Label and FormField.Hint by a generated id. You can customize this id by passing id to FormField.

Note: If you pass in a custom input that is not as Canvas Kit input, you will have to handle the error prop, validation and styling. For a custom approach, reference our Custom storybook example.

<FormField id='my-unique-id'> <FormField.Label>My Label Text</FormField.Label> <FormField.Input as={TextInput} onChange={(e) => console.log(e)} /> <FormField>

Layout Component

FormField.Input supports all props from thelayout component.

Props

Props extend from input. Changing the as prop will change the element interface.

NameTypeDescriptionDefault
cs

The cs prop takes in a single value or an array of values. You can pass the CSS class name returned by , or the result of and . If you're extending a component already using cs, you can merge that prop in as well. Any style that is passed to the cs prop will override style props. If you wish to have styles that are overridden by the css prop, or styles added via the styled API, use wherever elemProps is used. If your component needs to also handle style props, use instead.

import {handleCsProp} from '@workday/canvas-kit-styling'; import {mergeStyles} from '@workday/canvas-kit-react/layout'; // ... // `handleCsProp` handles compat mode with Emotion's runtime APIs. `mergeStyles` has the same // function signature, but adds support for style props. return ( <Element {...handleCsProp(elemProps, [ myStyles, myModifiers({ size: 'medium' }), myVars({ backgroundColor: 'red' }) ])} > {children} </Element> )
childrenReact.ReactNode
asReact.ElementType

Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using React.forwardRefand spread extra props to a root element.

Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care.

input
refReact.Ref<R = input>

Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If as is set to an element, it will be that element. If as is a component, the reference will be to that component (or element if the component uses React.forwardRef).

model

Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context.

elemPropsHook(
  model: ,
  elemProps: TProps
) => HTML Attributes

Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one.

useFormFieldInput

Adds the necessary props to an Input component. Used by the FormField.Input subcomponent and other input type components

(
  model: ,
  elemProps: {},
  ref: React.Ref
) => {
  required:  true | undefined;
  aria-invalid:  true | undefined;
  aria-describedby:  string | undefined;
  aria-labelledby:  string | undefined;
  id:  string | undefined;
  error:  'error' | 'caution' | undefined;
}

FormField.Label

FormField.Label will render a label element that has a matching id to the FormField.Input.

<FormField> <FormField.Label>First Name</FormField.Label> <FormField.Input as={TextInput} value={value} onChange={(e) => console.log(e)} /> </FormField>

Layout Component

FormField.Label supports all props from thelayout component.

Props

Props extend from label. Changing the as prop will change the element interface.

NameTypeDescriptionDefault
childrenReactNode

The text of the label.

isHiddenboolean

When true, will apply accessibleHide to the label. This is useful in cases where you still need accessibility but don't want to show the label, like a search input.

cs

The cs prop takes in a single value or an array of values. You can pass the CSS class name returned by , or the result of and . If you're extending a component already using cs, you can merge that prop in as well. Any style that is passed to the cs prop will override style props. If you wish to have styles that are overridden by the css prop, or styles added via the styled API, use wherever elemProps is used. If your component needs to also handle style props, use instead.

import {handleCsProp} from '@workday/canvas-kit-styling'; import {mergeStyles} from '@workday/canvas-kit-react/layout'; // ... // `handleCsProp` handles compat mode with Emotion's runtime APIs. `mergeStyles` has the same // function signature, but adds support for style props. return ( <Element {...handleCsProp(elemProps, [ myStyles, myModifiers({ size: 'medium' }), myVars({ backgroundColor: 'red' }) ])} > {children} </Element> )
variant 'error' | 'hint' | 'inverse'

Type variant token names: error, hint or inverse.

<Text variant="error" typeLevel="subtext.large">Error text</Text>
typeLevel
  'title.large'
   | 'title.medium'
   | 'title.small'
   | 'heading.large'
   | 'heading.medium'
   | 'heading.small'
   | 'subtext.large'
   | 'subtext.medium'
   | 'subtext.small'
   | 'body.large'
   | 'body.medium'
   | 'body.small'

Type token as string with level and size separated by dot. These values map to our Canvas type levels.

<Text typeLevel="body.small">Small body text</Text>
asReact.ElementType

Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using React.forwardRefand spread extra props to a root element.

Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care.

label
refReact.Ref<R = label>

Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If as is set to an element, it will be that element. If as is a component, the reference will be to that component (or element if the component uses React.forwardRef).

model

Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context.

elemPropsHook(
  model: ,
  elemProps: TProps
) => HTML Attributes

Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one.

useFormFieldLabel

Adds the necessary props to a Label component. Used by the FormField.Label subcomponent and other input type components

(
  model: ,
  elemProps: {},
  ref: React.Ref
) => {
  htmlFor: any;
  id: any;
}

FormField.Hint

FormField.Hint will render any additional information you want to provide to the FormField.Input. If you set the orientation prop to horizontal you should use FormField.Field to properly align the hint with your FormField.Input.

<FormField> <FormField.Label>First Name</FormField.Label> <FormField.Input as={TextInput} value={value} onChange={(e) => console.log(e)} /> <FormField.Hint>This is your hint text</FormField.Hint> </FormField>

Layout Component

FormField.Hint supports all props from thelayout component.

Props

Props extend from p. Changing the as prop will change the element interface.

NameTypeDescriptionDefault
typeLevel
  'title.large'
   | 'title.medium'
   | 'title.small'
   | 'heading.large'
   | 'heading.medium'
   | 'heading.small'
   | 'subtext.large'
   | 'subtext.medium'
   | 'subtext.small'
   | 'body.large'
   | 'body.medium'
   | 'body.small'

Type token as string with level and size separated by dot. These values map to our Canvas type levels.

<Text typeLevel="body.small">Small body text</Text>
variant 'error' | 'hint' | 'inverse'

Type variant token names: error, hint or inverse.

<Text variant="error" typeLevel="subtext.large">Error text</Text>
cs

The cs prop takes in a single value or an array of values. You can pass the CSS class name returned by , or the result of and . If you're extending a component already using cs, you can merge that prop in as well. Any style that is passed to the cs prop will override style props. If you wish to have styles that are overridden by the css prop, or styles added via the styled API, use wherever elemProps is used. If your component needs to also handle style props, use instead.

import {handleCsProp} from '@workday/canvas-kit-styling'; import {mergeStyles} from '@workday/canvas-kit-react/layout'; // ... // `handleCsProp` handles compat mode with Emotion's runtime APIs. `mergeStyles` has the same // function signature, but adds support for style props. return ( <Element {...handleCsProp(elemProps, [ myStyles, myModifiers({ size: 'medium' }), myVars({ backgroundColor: 'red' }) ])} > {children} </Element> )
childrenReactNode
asReact.ElementType

Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using React.forwardRefand spread extra props to a root element.

Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care.

p
refReact.Ref<R = p>

Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If as is set to an element, it will be that element. If as is a component, the reference will be to that component (or element if the component uses React.forwardRef).

model

Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context.

elemPropsHook(
  model: ,
  elemProps: TProps
) => HTML Attributes

Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one.

useFormFieldHint

Adds the necessary props to a Hint component. Used by the FormField.Hint subcomponent and other input type components

(
  model: ,
  elemProps: {},
  ref: React.Ref
) => {
  id: any;
}

FormField.Field

FormField.Field allows you to customize container alignment and styles when wrapping your input and hint text.

<FormField orientation="horizontalStart"> <FormField.Label>First Name</FormField.Label> <FormField.Field> <FormField.Input as={TextInput} value={value} onChange={(e) => console.log(e)} /> <FormField.Hint>This is your hint text</FormField.Hint> </FormField.Field> </FormField>

Props

Props extend from div. Changing the as prop will change the element interface.

NameTypeDescriptionDefault
cs

The cs prop takes in a single value or an array of values. You can pass the CSS class name returned by , or the result of and . If you're extending a component already using cs, you can merge that prop in as well. Any style that is passed to the cs prop will override style props. If you wish to have styles that are overridden by the css prop, or styles added via the styled API, use wherever elemProps is used. If your component needs to also handle style props, use instead.

import {handleCsProp} from '@workday/canvas-kit-styling'; import {mergeStyles} from '@workday/canvas-kit-react/layout'; // ... // `handleCsProp` handles compat mode with Emotion's runtime APIs. `mergeStyles` has the same // function signature, but adds support for style props. return ( <Element {...handleCsProp(elemProps, [ myStyles, myModifiers({ size: 'medium' }), myVars({ backgroundColor: 'red' }) ])} > {children} </Element> )
childrenReact.ReactNode
asReact.ElementType

Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using React.forwardRefand spread extra props to a root element.

Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care.

div
refReact.Ref<R = div>

Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If as is set to an element, it will be that element. If as is a component, the reference will be to that component (or element if the component uses React.forwardRef).

model

Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context.

elemPropsHook(
  model: ,
  elemProps: TProps
) => HTML Attributes

Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one.

Model

useFormFieldModel

useFormFieldModel (config: ):

Content Guidelines

  • Reference the Form  pattern for more information on designing forms and strategies to enable the best user experience of form content.