useTextField

Provides the behavior and accessibility implementation for a text field.

installyarn add react-aria
version3.19.0
usageimport {useTextField} from 'react-aria'

API#


useTextField<T extends TextFieldIntrinsicElements = DefaultElementType>( (props: AriaTextFieldOptions<T>, , ref: TextFieldRefObject<T> )): TextFieldAria<T>

Features#


Text fields can be built with <input> or <textarea> and <label> elements, but you must manually ensure that they are semantically connected via ids for accessibility. useTextField helps automate this, and handle other accessibility features while allowing for custom styling.

  • Built with a native <input> or <textarea> element
  • Visual and ARIA labeling support
  • Change, clipboard, composition, selection, and input event support
  • Required and invalid states exposed to assistive technology via ARIA
  • Support for description and error message help text linked to the input via ARIA

Anatomy#


ValueLabelInputLabelHelp textDescription or error message

Text fields consist of an input element and a label. useTextField automatically manages the relationship between the two elements using the for attribute on the <label> element and the aria-labelledby attribute on the <input> element.

useTextField also supports optional description and error message elements, which can be used to provide more context about the field, and any validation messages. These are linked with the input via the aria-describedby attribute.

useTextField returns props that you should spread onto the appropriate element:

NameTypeDescription
inputPropsTextFieldInputProps<TextFieldIntrinsicElements>Props for the input element.
labelPropsDOMAttributesProps for the text field's visible label element, if any.
descriptionPropsDOMAttributesProps for the text field's description element, if any.
errorMessagePropsDOMAttributesProps for the text field's error message element, if any.

If there is no visual label, an aria-label or aria-labelledby prop must be passed instead to identify the element to screen readers.

Example#


import {useTextField} from 'react-aria';

function TextField(props) {
  let { label } = props;
  let ref = React.useRef();
  let { labelProps, inputProps, descriptionProps, errorMessageProps } =
    useTextField(props, ref);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', width: 200 }}>
      <label {...labelProps}>{label}</label>
      <input {...inputProps} ref={ref} />
      {props.description && (
        <div {...descriptionProps} style={{ fontSize: 12 }}>
          {props.description}
        </div>
      )}
      {props.errorMessage &&
        (
          <div {...errorMessageProps} style={{ color: 'red', fontSize: 12 }}>
            {props.errorMessage}
          </div>
        )}
    </div>
  );
}

<TextField label="Email" />
import {useTextField} from 'react-aria';

function TextField(props) {
  let { label } = props;
  let ref = React.useRef();
  let {
    labelProps,
    inputProps,
    descriptionProps,
    errorMessageProps
  } = useTextField(props, ref);

  return (
    <div
      style={{
        display: 'flex',
        flexDirection: 'column',
        width: 200
      }}
    >
      <label {...labelProps}>{label}</label>
      <input {...inputProps} ref={ref} />
      {props.description &&
        (
          <div
            {...descriptionProps}
            style={{ fontSize: 12 }}
          >
            {props.description}
          </div>
        )}
      {props.errorMessage &&
        (
          <div
            {...errorMessageProps}
            style={{ color: 'red', fontSize: 12 }}
          >
            {props.errorMessage}
          </div>
        )}
    </div>
  );
}

<TextField label="Email" />
import {useTextField} from 'react-aria';

function TextField(
  props
) {
  let { label } = props;
  let ref = React
    .useRef();
  let {
    labelProps,
    inputProps,
    descriptionProps,
    errorMessageProps
  } = useTextField(
    props,
    ref
  );

  return (
    <div
      style={{
        display: 'flex',
        flexDirection:
          'column',
        width: 200
      }}
    >
      <label
        {...labelProps}
      >
        {label}
      </label>
      <input
        {...inputProps}
        ref={ref}
      />
      {props
        .description &&
        (
          <div
            {...descriptionProps}
            style={{
              fontSize:
                12
            }}
          >
            {props
              .description}
          </div>
        )}
      {props
        .errorMessage &&
        (
          <div
            {...errorMessageProps}
            style={{
              color:
                'red',
              fontSize:
                12
            }}
          >
            {props
              .errorMessage}
          </div>
        )}
    </div>
  );
}

<TextField label="Email" />

Text area#

useTextField also supports multi-line text entry with the <textarea> element via the inputElementType prop.

import {useTextField} from 'react-aria';

function TextArea(props) {
  let { label } = props;
  let ref = React.useRef();
  let { labelProps, inputProps } = useTextField({
    ...props,
    inputElementType: 'textarea'
  }, ref);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', width: 200 }}>
      <label {...labelProps}>{label}</label>
      <textarea {...inputProps} ref={ref} />
    </div>
  );
}

<TextArea label="Description" />
import {useTextField} from 'react-aria';

function TextArea(props) {
  let { label } = props;
  let ref = React.useRef();
  let { labelProps, inputProps } = useTextField({
    ...props,
    inputElementType: 'textarea'
  }, ref);

  return (
    <div
      style={{
        display: 'flex',
        flexDirection: 'column',
        width: 200
      }}
    >
      <label {...labelProps}>{label}</label>
      <textarea {...inputProps} ref={ref} />
    </div>
  );
}

<TextArea label="Description" />
import {useTextField} from 'react-aria';

function TextArea(
  props
) {
  let { label } = props;
  let ref = React
    .useRef();
  let {
    labelProps,
    inputProps
  } = useTextField({
    ...props,
    inputElementType:
      'textarea'
  }, ref);

  return (
    <div
      style={{
        display: 'flex',
        flexDirection:
          'column',
        width: 200
      }}
    >
      <label
        {...labelProps}
      >
        {label}
      </label>
      <textarea
        {...inputProps}
        ref={ref}
      />
    </div>
  );
}

<TextArea label="Description" />

Usage#


The following examples show how to use the TextField component created in the above example.

Default value#

A TextField's value is empty by default, but an initial, uncontrolled, value can be provided using the defaultValue prop.

<TextField
  label="Email"
  defaultValue="me@email.com" />
<TextField
  label="Email"
  defaultValue="me@email.com" />
<TextField
  label="Email"
  defaultValue="me@email.com"
/>

Controlled value#

The value prop can be used to make the value controlled. The onChange event is fired when the user edits the text, and receives the new value.

function Example() {
  let [text, setText] = React.useState();

  return (
    <>
      <TextField label="Your text" onChange={setText} />
      <p>Mirrored text: {text}</p>
    </>
  );
}
function Example() {
  let [text, setText] = React.useState();

  return (
    <>
      <TextField label="Your text" onChange={setText} />
      <p>Mirrored text: {text}</p>
    </>
  );
}
function Example() {
  let [text, setText] =
    React.useState();

  return (
    <>
      <TextField
        label="Your text"
        onChange={setText}
      />
      <p>
        Mirrored text:
        {' '}
        {text}
      </p>
    </>
  );
}

Description#

The description prop can be used to associate additional help text with a text field.

<TextField
  label="Email"
  description="Enter an email for us to contact you about your order."
/>
<TextField
  label="Email"
  description="Enter an email for us to contact you about your order."
/>
<TextField
  label="Email"
  description="Enter an email for us to contact you about your order."
/>

Error message#

The errorMessage prop can be used to help the user fix a validation error. It should be combined with the validationState prop to semantically mark the input element as invalid for assistive technologies.

<TextField
  label="Email"
  validationState="invalid"
  errorMessage="Please enter a valid email address." />
<TextField
  label="Email"
  validationState="invalid"
  errorMessage="Please enter a valid email address." />
<TextField
  label="Email"
  validationState="invalid"
  errorMessage="Please enter a valid email address."
/>

Disabled#

A TextField can be disabled using the isDisabled prop.

<TextField label="Email" isDisabled />
<TextField label="Email" isDisabled />
<TextField
  label="Email"
  isDisabled
/>

Read only#

The isReadOnly boolean prop makes the TextField's text content immutable. Unlike isDisabled, the TextField remains focusable and the contents can still be copied. See the MDN docs for more information.

<TextField label="Email" defaultValue="abc@adobe.com" isReadOnly />
<TextField
  label="Email"
  defaultValue="abc@adobe.com"
  isReadOnly
/>
<TextField
  label="Email"
  defaultValue="abc@adobe.com"
  isReadOnly
/>

Required#

A TextField can be marked as required using the isRequired prop. This is exposed to assistive technologies by React Aria. It's your responsibility to add additional visual styling if needed.

<TextField label="Email" isRequired />
<TextField label="Email" isRequired />
<TextField
  label="Email"
  isRequired
/>

HTML forms#

TextField supports the name prop for integration with HTML forms. In addition, attributes such as type, pattern, inputMode, and others are passed through to the underlying <input> element.

<TextField label="Email" name="email" type="email" />
<TextField label="Email" name="email" type="email" />
<TextField
  label="Email"
  name="email"
  type="email"
/>

Internationalization#


RTL#

In right-to-left languages, text fields should be mirrored. The label should be right aligned, along with the text in the text field. Ensure that your CSS accounts for this.