useTextField
Provides the behavior and accessibility implementation for a text field.
install | yarn add react-aria |
---|---|
version | 3.35.1 |
usage | import {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
- Support for native HTML constraint validation with customizable UI, custom validation functions, realtime validation, and server-side validation errors
- Support for description and error message help text linked to the input via ARIA
Anatomy#
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:
Name | Type | Description |
inputProps | TextFieldInputProps<TextFieldIntrinsicElements> | Props for the input element. |
labelProps | DOMAttributes | LabelHTMLAttributes<HTMLLabelElement> | Props for the text field's visible label element, if any. |
descriptionProps | DOMAttributes | Props for the text field's description element, if any. |
errorMessageProps | DOMAttributes | Props for the text field's error message element, if any. |
isInvalid | boolean | Whether the input value is invalid. |
validationErrors | string[] | The current error messages for the input if it is invalid, otherwise an empty array. |
validationDetails | ValidityState | The native validation details for the input. |
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 type {AriaTextFieldProps} from 'react-aria';
import {useTextField} from 'react-aria';
function TextField(props: AriaTextFieldProps) {
let { label } = props;
let ref = React.useRef(null);
let {
labelProps,
inputProps,
descriptionProps,
errorMessageProps,
isInvalid,
validationErrors
} = 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>
)}
{isInvalid && (
<div {...errorMessageProps} style={{ color: 'red', fontSize: 12 }}>
{validationErrors.join(' ')}
</div>
)}
</div>
);
}
<TextField label="Email" />
import type {AriaTextFieldProps} from 'react-aria';
import {useTextField} from 'react-aria';
function TextField(props: AriaTextFieldProps) {
let { label } = props;
let ref = React.useRef(null);
let {
labelProps,
inputProps,
descriptionProps,
errorMessageProps,
isInvalid,
validationErrors
} = 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>
)}
{isInvalid && (
<div
{...errorMessageProps}
style={{ color: 'red', fontSize: 12 }}
>
{validationErrors.join(' ')}
</div>
)}
</div>
);
}
<TextField label="Email" />
import type {AriaTextFieldProps} from 'react-aria';
import {useTextField} from 'react-aria';
function TextField(
props:
AriaTextFieldProps
) {
let { label } = props;
let ref = React.useRef(
null
);
let {
labelProps,
inputProps,
descriptionProps,
errorMessageProps,
isInvalid,
validationErrors
} = 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>
)}
{isInvalid && (
<div
{...errorMessageProps}
style={{
color: 'red',
fontSize: 12
}}
>
{validationErrors
.join(' ')}
</div>
)}
</div>
);
}
<TextField label="Email" />
Text area#
useTextField
also supports multi-line text entry with the <textarea>
element via the inputElementType
prop.
import type {AriaTextFieldProps} from 'react-aria';
import {useTextField} from 'react-aria';
function TextArea(props: AriaTextFieldProps<HTMLTextAreaElement>) {
let { label } = props;
let ref = React.useRef(null);
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 type {AriaTextFieldProps} from 'react-aria';
import {useTextField} from 'react-aria';
function TextArea(
props: AriaTextFieldProps<HTMLTextAreaElement>
) {
let { label } = props;
let ref = React.useRef(null);
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 type {AriaTextFieldProps} from 'react-aria';
import {useTextField} from 'react-aria';
function TextArea(
props:
AriaTextFieldProps<
HTMLTextAreaElement
>
) {
let { label } = props;
let ref = React.useRef(
null
);
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."
/>
Validation#
useTextField supports HTML constraint validation props such as isRequired
, type="email"
, minLength
, and pattern
, as well as custom validation functions, realtime validation, and server-side validation. It can also be integrated with other form libraries. See the Forms guide to learn more.
When a TextField has the validationBehavior="native"
prop, validation errors block form submission. To display validation errors, use the validationErrors
and errorMessageProps
returned by useTextField
. This allows you to render error messages from all of the above sources with consistent custom styles.
<form>
<TextField
label="Email"
name="email"
type="email"
isRequired
validationBehavior="native" />
<input type="submit" style={{marginTop: 8}} />
</form>
<form>
<TextField
label="Email"
name="email"
type="email"
isRequired
validationBehavior="native" />
<input type="submit" style={{marginTop: 8}} />
</form>
<form>
<TextField
label="Email"
name="email"
type="email"
isRequired
validationBehavior="native" />
<input
type="submit"
style={{
marginTop: 8
}}
/>
</form>
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.