Text Input
UI pattern
textbox role and an accessible name, declares when it's required, explains a rejected entry with a message it references, and accepts typing from the keyboard.A single-line text input takes one line, such as a name, an email address, or a search term. A multiline text input, most often a <textarea>, accepts line breaks for longer answers such as a comment or a postal address.
A text input rarely works alone. A label says what to enter, a description can explain the expected format, and an error message says what to fix when an entry is rejected. When the field is in a form, its value is submitted with the rest of the form's data.
Build a text input with the native <input> or <textarea> element whenever you can. Browsers supply the role, the editing keys, the required and disabled states, and constraint validation, and they submit the value with the form.
A custom text input, built from a generic element with contenteditable, has to recreate all of that with ARIA and code, and it's rarely worth the cost. Its value isn't part of a form's data at all unless it's built as a form-associated custom element.
A combobox is most often based on a text input: it is a text input that gets help from a popup of values to choose from. An <input> with a list attribute is a combobox.
When to Use
Use a text input when:
- Users need to enter text, such as a name, an address, or a search term.
- Users type a value with a set format, such as an email address, a phone number, or a date.
- Users need to write more than one line, such as a comment or a message. Use a multiline text input.
Do not use a text input when:
- Users choose from a fixed set of options. Use a listbox, a combobox, a radio group, or a set of checkboxes.
- Users set a value with a control built for it rather than typing it, such as a date picker, a color picker, or a slider. Use that control, such as
<input type="date">,<input type="color">, or<input type="range">. - Users need to enter a password. Use the native
<input type="password">element so that browsers and assistive technology can treat it as a protected field.
Examples
Code in this section is meant to demonstrate techniques rather than requirements and lacks features needed in a production application.
Both examples collect a value in a form. The native build reports validation errors to every user. The custom build shows what a generic element has to add to act as a text input.
Native Text Input With Validation
The form sets novalidate, so the script reports errors instead of the browser's own message bubble, while required and type="email" still define what counts as valid. The field references a hint with aria-describedby, and the script adds the error message only once validation fails.
Native text input HTML
<form id="signup" novalidate>
<label for="email">Email address</label>
<input
type="email"
id="email"
name="email"
required
aria-describedby="email-hint">
<p id="email-hint">
We'll send your receipt here.
</p>
<p id="email-error"></p>
<button type="submit">Sign up</button>
</form>CSS styles the error state from aria-invalid, so what sighted users see and what assistive technology reports come from the same attribute. A pseudo-class such as :user-invalid can flag a field before the script does, and the two states then disagree.
Native text input CSS
input[aria-invalid="true"] {
border: 2px solid darkred;
background-color: #fff0f0;
}
#email-error {
color: darkred;
}On a failed submit, the script writes a message that states the rule, sets aria-invalid="true", adds the message to aria-describedby, and moves focus to the field, so screen reader users hear the label, the error, and the hint together. Once the value is valid, it clears the message, the reference, and the invalid state.
Native text input JavaScript
const form = document.getElementById("signup")
const email = document.getElementById("email")
const error = document.getElementById("email-error")
function showError(message) {
error.textContent = message
if (message) {
email.setAttribute("aria-invalid", "true")
email.setAttribute(
"aria-describedby",
"email-error email-hint"
)
} else {
email.removeAttribute("aria-invalid")
email.setAttribute("aria-describedby", "email-hint")
}
}
form.addEventListener("submit", (event) => {
if (email.validity.valueMissing) {
showError("Enter your email address.")
} else if (email.validity.typeMismatch) {
showError(
"Enter an email address in the form name@example.com."
)
} else {
showError("")
return
}
event.preventDefault()
email.focus()
})
// clear the error as soon as the value is valid
email.addEventListener("input", () => {
if (
email.hasAttribute("aria-invalid") &&
email.checkValidity()
) {
showError("")
}
})Custom ARIA Text Input
A generic element becomes a text input with role="textbox" and contenteditable. The value plaintext-only stops users from pasting formatted text into a field meant to hold plain text. aria-labelledby names the field from visible text, and aria-required declares the requirement a native input would carry in required.
ARIA text input HTML
<span id="city-label">City</span>
<div
role="textbox"
contenteditable="plaintext-only"
aria-labelledby="city-label"
aria-required="true">
</div>contenteditable inserts a line break on Enter, so the script prevents that to keep the field single-line, and it tracks the value with the input event. The value still isn't submitted with a form. That takes a form-associated custom element.
ARIA text input JavaScript
const textbox = document.querySelector('[role="textbox"]')
// keep the field single-line
textbox.addEventListener("keydown", (event) => {
if (event.key === "Enter") {
event.preventDefault()
}
})
// track the value as it changes
textbox.addEventListener("input", () => {
const value = textbox.textContent
// validate and store the value here
})Structure and Semantics
Users need to know what a text input is for, whether an entry is required, and whether the entry they've made is valid. A native <input> or <textarea> conveys these through its own attributes and the browser's constraint validation, so ARIA that restates them adds nothing and can drift out of step with them. The exception is validation your code does itself: then the field reports the result with aria-invalid.
An <input> with no type, or with type set to text, email, tel, or url, exposes the textbox role, and so does <textarea>. type="search" exposes searchbox, a specialized textbox. Adding a list attribute makes any of them a combobox.
A native <input> or <textarea> supplies the keyboard behavior, the validation, and the states that a custom text input has to recreate, so build a custom one only with a specific reason. A custom text input sets ARIA attributes for what a native field conveys on its own. They change what assistive technology reports, not how the element behaves, so code still has to supply the behavior.
| ARIA attribute | Native equivalent | What it does |
|---|---|---|
role="textbox" | <input>, <textarea> | Identifies the element as a text input. |
aria-labelledby, aria-label | <label> | Names the field, from visible text with aria-labelledby or with aria-label when there's none. |
aria-describedby | None: native fields use it too | References a description, such as the expected format or an error message. |
aria-placeholder | placeholder | Gives a brief hint, such as a sample value. It isn't a label, since it disappears once users type. |
aria-required="true" | required | Declares that an entry is required. |
aria-multiline="true" | <textarea> | Declares that the field accepts line breaks. |
aria-readonly="true" | readonly | Declares that users can read and copy the value but not change it. |
aria-invalid="true" | Constraint validation, for the browser's own rules | Reports that the value failed validation. Set it when your code validates the field, as with novalidate or a rule the browser doesn't know. |
aria-disabled="true" | disabled | Reports that the field is unavailable. |
Role
A text input exposes the textbox role, or searchbox for a search field, on the element users focus and type into. A <textarea>, and the types of <input> that accept direct text entry, carry the role implicitly. A custom text input declares role="textbox" on its editable element.
Has the correct role
Reported as: Element has incorrect role
A text input must expose the textbox role, or searchbox for a search field.
When a custom field built from a <div> or <span> has no role, or the wrong one, assistive technology reports it as plain text or as a different kind of control, and users aren't told they can type into it.
Use a <textarea> or an <input> of a type that accepts direct text entry, which carries the role implicitly. When the field has to be custom, set role="textbox" on the editable element.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Applies role to the correct element
Reported as: Incorrect root element
Sanity check. Evinced checks that the textbox role sits on the same element that takes focus and accepts typing. This check runs on every UI pattern, not only on text inputs.
A text input should carry its role on the same element that takes focus and accepts typing.
When role="textbox" sits on a wrapper and contenteditable sits on a child inside it, or the other way around, focus lands on an element with no role. Users are told nothing about what they've reached, even though the role is in the markup.
Put the role, the accessible name, contenteditable, and the state attributes on one element, and keep any layout wrapper free of roles.
Accessibility Label
A text input's accessible name tells users what to enter before they start typing. A <label> element names a native input, either by wrapping it or by pointing at it with for, and aria-labelledby names any text input from visible text elsewhere. Placeholder text isn't a label: it's the weakest source of a name, and it disappears once users type.
The following example shows two more ways to name a text input: a <label> that wraps the field, and an aria-label on a custom field with no visible label.
<!-- The wrapping label names the input -->
<label>
Full name
<input type="text" name="full-name">
</label>
<!-- With no visible label, aria-label names the field -->
<div
role="textbox"
contenteditable="plaintext-only"
aria-label="Search the catalog">
</div>Names a container that needs one
Reported as: Missing contextual labeling
A text input must have an accessibility label that says what to enter.
When the field's label sits beside it on screen with nothing associating the two, or when placeholder text is the only prompt, screen reader users reach a field identified by its role alone. They can't tell what it asks for, so they can't fill it in with any confidence. The placeholder also disappears as soon as anyone types.
Associate a visible label with the field, using a <label> element on a native input or aria-labelledby on a custom one. Use aria-label only when there's no visible text to point at.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Required Input
A required text input says so programmatically as well as visually. The required attribute on a native <input> or <textarea> conveys the state and turns on the browser's check for an empty value. A custom text input sets aria-required="true" and enforces the requirement in code. When the form marks required fields with an asterisk, explain the convention in text before the first field.
Declares that a field is required
Reported as: Asterisk fields not marked as required; Required field is missing required attribute
A text input that has to be filled in must declare that it's required.
When an asterisk in the label, a marker added by CSS, or a note in smaller text is the only sign, screen reader users hear every field as optional. They find out which ones mattered when the form refuses to submit, and on a long form that can happen more than once. A marker drawn by CSS isn't in the text a screen reader reads at all.
Add required to a native input or aria-required="true" to a custom one wherever the visible marking appears, and generate both from the same field definition.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Disabled
A disabled text input is reported as unavailable, and its value isn't submitted with the form. A native <input> or <textarea> takes the disabled attribute, and a custom text input takes aria-disabled="true" along with code that stops it from accepting entry. When users should still read the value and have it submitted, but not edit it, make the field read-only instead.
Avoids conflicting disabled states
Reported as: Conflicting disabled values
A text input must declare its disabled state one way.
When a native input carries disabled alongside aria-disabled="false", or the two otherwise disagree, assistive technology can report a different state from the one the browser enforces. Users can't tell whether the field will take their entry.
Use disabled on a native input or aria-disabled on a custom one, never both.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Uses aria-disabled rather than disabled
Reported as: Element does not support the disabled attribute
A custom text input must convey its disabled state with aria-disabled, not the disabled attribute.
Browsers ignore disabled on a <div> or a <span>, so the field stays in the accessibility tree as an available text input however it's styled. Screen reader users are told they can type into a field the design means to be unavailable.
Set aria-disabled="true", and in the same step set contenteditable="false" so the field stops accepting entry. When a native <input> would do the job, prefer it: its disabled attribute carries the state and the behavior together.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Disables only elements that support it
Reported as: Element type does not support disabled state
An element in a text input must carry disabled or aria-disabled only when its role supports a disabled state.
When the state sits on an element whose role has none, such as a wrapper, a list item or a heading, assistive technology may drop it or report it on something users can't operate, while the control that really is unavailable is still reported as available.
Remove the attribute from that element, and set the disabled state on the control itself, using an element or role that supports it, such as a native <button>.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Forbidden Interactive Children
A text input contains its value and, at most, presentational content, such as an icon repeating information the field already exposes. A clear button, a password reveal toggle, or a search button sits beside the field, not inside it or inside a custom field's container.
Avoids nested interactives
Reported as: Forbidden interactive children; Nested interactive elements
A text input must not contain another interactive element, such as a button or a link.
Everything inside a textbox is expected to be presentational, so a nested control can lose its role and name and drop out of the accessibility tree while it's still visible. Keyboard users may be unable to focus it. Owning the control through aria-owns counts as containing it.
Move the control out and place it next to the field as a sibling, with its own role, accessible name, and tab stop.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Relationships
A text input depends on the elements around it. A label names it, a description or error message explains it, and a form collects its value.
A native input takes its name from a <label> element that wraps it or points at it with for. Any text input can instead reference visible text with aria-labelledby. Helper text and error messages are referenced with aria-describedby, and when the referenced message is an error, the field also carries aria-invalid="true".
A native input belongs to the form it sits inside. When the layout has to place it elsewhere, its form attribute names the form by id and includes the value in the form's data. An aria-owns attribute doesn't do that. A custom text input's value reaches the form's data only when it's built as a form-associated custom element.
aria-owns
A text input has nothing to own. Its content is its value plus, at most, a presentational icon, all of it already inside the field in the DOM.
Avoids aria-owns
Reported as: Avoid aria-owns
General check. Evinced checks that a text input states its structure through the DOM rather than with aria-owns. This check runs on every UI pattern, not only on text inputs.
A text input should not use aria-owns.
When a custom text input lists its own icon or text in aria-owns, the attribute restates what the DOM already nests, and support for it varies across assistive technology, so users can get a different structure depending on their software. Owning a clear button or another control makes it a child of the field, where screen reader users may not hear its role or name.
Remove aria-owns. Keep the field's content inside it in the DOM, and place any control beside the field as a sibling.
Operation
Users place a cursor in a text input, type and edit its value, and move on, with a pointer or with a keyboard alone. A native <input> or <textarea> provides all of this. A custom text input gets text entry and editing from contenteditable and has to supply the rest in code.
Clicking or tapping the field moves focus into it and places the cursor. Users then type with a physical or on-screen keyboard, move the cursor by clicking a new position, select text by dragging, and delete, overwrite, or paste over the selection. A clear button beside the field empties it.
Typing inserts characters at the cursor. These keys move focus to the text input, move the cursor through its value, and edit it:
| Key | Function |
|---|---|
| Tab | Moves focus to the text input. |
| Shift + Tab | Moves focus back to the previous element. |
| Left Arrow, Right Arrow | Move the cursor one character. |
| Control + Left Arrow, Control + Right Arrow (Option on macOS) | Move the cursor one word. |
| Home | Moves the cursor to the start of the value. |
| End | Moves the cursor to the end of the value. |
| Shift + any cursor movement key | Extends the selection. |
| Control + A (Command + A on macOS) | Selects the whole value. |
| Backspace | Deletes the character before the cursor, or the selection. |
| Delete | Deletes the character after the cursor, or the selection. |
| Control + C, Control + X, Control + V (Command on macOS) | Copy, cut, and paste. |
| Enter | In a single-line text input, submits the form the field belongs to. In a multiline text input, inserts a line break. |
| Shift + Enter | Inserts a line break in a multiline text input where Enter sends a message, as in a chat. |
contenteditable inserts a line break on Enter and never submits a form. A single-line custom text input listens for keydown and prevents the line break, and it submits the form in code when it should behave like a native field. Track the value with the input event rather than the deprecated keypress event, which behaves inconsistently across browsers and doesn't fire reliably for the input methods used to type many languages.
Focus Sequence
An enabled text input is one tab stop, and a disabled one isn't in the tab order. A native <input> or <textarea> is focusable on its own, and so is an element with contenteditable, unless it's nested inside another editable element, where it needs tabindex="0". A read-only field stays in the tab order, so users can reach its value and copy it.
Reachable by keyboard
Reported as: Keyboard accessible
A text input must be reachable with the Tab key.
When a custom text input is built from a <div> or a <span> with role="textbox" but no contenteditable or tabindex, keyboard users can't reach it or fill it in.
Use a native <input> or <textarea>. When the field has to be custom, contenteditable makes it focusable. Add tabindex="0" when it sits inside another editable element, and don't use a positive tabindex.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Skips tab order when disabled
Reported as: Disabled element focusable
A text input that presents as disabled shouldn't be a stop in the tab order.
When a field styled and scripted as disabled keeps its tab stop, keyboard users land on something they can't type into, with no sign of how many more such stops are coming.
Use the disabled attribute on a native input, which removes the tab stop. On a custom text input, set contenteditable="false" and tabindex="-1" while it's disabled, and restore both when it's available again. If you keep a disabled field focusable so users can learn why it's unavailable, make sure aria-disabled="true" is set.
Severity: Minor
Element that carries role receives focus
Reported as: Focusable offset
A text input must take focus on the element that carries its role, not on a descendant.
When role="textbox" sits on a wrapper and focus lands on an editable child inside it, the focused element has no role. Screen reader users tabbing through the form aren't told they've reached a text field, so they may not realize they can type there.
Keep the role, contenteditable, and the tab stop on one element, and remove focusability from the descendant.
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Context Change
Typing into a text input can update the page in place, such as filtering a list of results, but it doesn't submit the form, load a new page, or move focus. Unless text before the field says otherwise, those start from an explicit action, such as pressing Enter or activating a button.
Keeps context when a value changes
Reported as: Unexpected context change on input
A text input must not change the context as its value changes unless users are told beforehand that it will.
When a field submits the form, loads a new page, or moves focus to the next field as soon as it holds a certain number of characters, screen reader and screen magnifier users may not notice the page changed under them. Users who type a correction or paste a value lose their place, and a form that submits partway can discard what they hadn't finished.
Update the page in place and leave focus in the field. Start navigation, submission, and focus moves from Enter or a button. When a change of context is intended, say so in text before the field.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 3.2.2 On Input (A) | Changing the setting of any user interface component does not automatically cause a change of context unless the user has been advised of the behavior before using the component. |
| EN 301 549 | 9.3.2.2 On Input | Same as the WCAG text. |
| Section 508 | 1194.22(n) | When electronic forms are designed to be completed on-line, the form shall allow people using assistive technology to access the information, field elements, and functionality required for completion and submission of the form, including all directions and cues. |
| Section 508 | 1194.21(l) | When electronic forms are used, the form shall allow people using assistive technology to access the information, field elements, and functionality required for completion and submission of the form, including all directions and cues. |
Event Listener Type
When script in a text input responds to keys, it listens for keydown or keyup. The keypress event is deprecated, and browsers don't fire it for many keys, including the arrow keys, Home, End and Escape.
Avoids the keypress event
Reported as: Deprecated keypress listener
A text input's key handling should use keydown or keyup, not keypress.
When a handler listens for keypress, keys the browser doesn't send through that event go unanswered, and keyboard users find the text input ignoring keys it's meant to respond to.
Replace each keypress listener with a keydown listener, and read the key from event.key.
Severity: Minor
Typed Input
A text input takes what users type when it says it can be edited, and refuses it when it says it can't. A native <input> or <textarea> gets both from the browser, including through its readonly and disabled attributes. A custom text input gets typing from contenteditable, while aria-readonly and aria-disabled only change what assistive technology reports, so code has to stop the typing while either applies.
Takes typed text into its value
Reported as: Text input value not updated with keyboard
A text input that can be edited must add the characters users type to its value.
When a keydown handler calls event.preventDefault() for every key, or a field that filters its input never writes the accepted characters back, typing does nothing. Keyboard-only users, and speech input users whose dictation arrives as typing, can't enter anything, and nothing on screen says why.
Cancel only the specific keys the script handles itself, and write every accepted character to the value. When the field isn't meant to be edited, mark it read-only instead of suppressing keystrokes.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Ignores typing when not editable
Reported as: Non-editable text input accepts input
A text input declared read-only or disabled must not accept typed characters.
When a custom field carries aria-readonly="true" or aria-disabled="true" but typing still changes its value, screen reader users are told the value is fixed and leave it alone, while anyone typing into the field can change it by accident.
Prefer a native input with readonly or disabled, which the browser enforces. On a custom text input, set contenteditable="false" while the state applies, and keep a read-only field focusable so users can still read and copy its value. If the field is meant to be editable, remove the attribute instead.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Newline Input
Only a text input that collects several lines should be multiline: a <textarea> for a comment or an address, and a single-line <input> for a name or a reference number. A <textarea> inserts a line break on Enter. A custom text input is single-line unless it sets aria-multiline="true", which tells users that Enter breaks the line, and its script has to make that true.
The following example shows a native and a custom multiline text input.
<!-- Native multiline text input -->
<label for="message">Message</label>
<textarea
id="message"
name="message"
rows="5"></textarea>
<!-- Custom multiline text input -->
<span id="tags-label">Tags for the article</span>
<div
role="textbox"
contenteditable="plaintext-only"
aria-multiline="true"
aria-labelledby="tags-label">
</div>Breaks lines from the keyboard
Reported as: Multiline input does not insert a new line
A multiline text input must let users insert a line break from the keyboard.
When a script cancels Enter to send a message or submit the form and no other key inserts a break, keyboard users can't write an address or a message that needs more than one line. Screen reader users, told the field is multiline, may press Enter to break a line and send a message they hadn't finished.
Make sure at least one key inserts a line break. When Enter sends, let Shift + Enter insert the break, and say so in the field's instructions. When the field should only hold one line, use an <input> or remove aria-multiline="true".
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Input Validation
When a text input's value fails validation, the field reports itself invalid and references a message saying what's wrong and what's expected. It references the message only while aria-invalid is "true": until then it carries no aria-invalid, or carries false, and no reference to the message. Drive the state, the message, and the reference from the same validation result, and clear all three once the value is valid, as the build under Examples does.
State any required format or length limit in text the field references, so users know the rule before an entry is rejected.
Explains why an entry was rejected
Reported as: Missing accessible error notification
A text input whose value is rejected must be associated with a message that says what was wrong.
When a red border is the whole error state, or the message beside the field isn't referenced from it, screen reader users get a form that refuses their entry and gives no reason. Each guess means re-entering data and submitting again.
State the rule in the message, such as "Enter a date in the form 12 March 2026", and reference it with aria-describedby. Move focus to the first rejected field on submit, and when errors appear as users move through the form, announce them in a live region too.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 3.3.1 Error Identification (A) | If an input error is automatically detected, the item that is in error is identified and the error is described to the user in text. |
| EN 301 549 | 9.3.3.1 Error Identification | Same as the WCAG text. |
| Section 508 | 1194.21(l) | When electronic forms are used, the form shall allow people using assistive technology to access the information, field elements, and functionality required for completion and submission of the form, including all directions and cues. |
| Section 508 | 1194.22(n) | When electronic forms are designed to be completed on-line, the form shall allow people using assistive technology to access the information, field elements, and functionality required for completion and submission of the form, including all directions and cues. |
Points to the error with aria-describedby
Reported as: Avoid aria-errormessage
A text input should reference its error message with aria-describedby rather than aria-errormessage.
Assistive technology supports aria-describedby far more widely than aria-errormessage. When a rejected entry's message is referenced only with aria-errormessage, the markup passes review while many screen reader users hear a field that seems to have nothing wrong with it.
Reference the message with aria-describedby instead.
Severity: Serious
Validates in code, not by attribute
Reported as: Non-semantic input has type attribute
A custom text input must enforce any constraint its attributes declare.
When a <div> with role="textbox" carries type="email", pattern, minlength, or maxlength, the browser applies none of them. The markup reads as constrained while the field accepts anything, so users learn about the rule from a server rejection, far from the field where they could have fixed it.
Prefer a native <input>, which honors these attributes. When the field has to stay custom, remove them, enforce the rule in code, and state it in a description the field references.
Severity: Serious
Flags the field that failed
Reported as: aria-invalid did not update
A text input whose value fails validation must report itself invalid.
When the error state is only a CSS class, screen reader users moving through the form after a failed submit hear every field as normal. When aria-invalid="true" stays set after the value is corrected, users are told a valid entry is wrong and may change it.
Set aria-invalid="true" when validation fails, and remove it or set it to false when the value becomes valid, driving both from the same result. Flag the field when validation runs on blur or submit, not on every keystroke.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Required Input Notification
When a submission is refused because a required text input is empty, the field explains the problem: a visible message says what's missing, the field references it, and the field reports itself invalid. The field references the message only while aria-invalid is "true". Marking the field required beforehand means most users never reach this state.
Points to the error with aria-describedby
Reported as: Avoid aria-errormessage
A text input should reference its error message with aria-describedby rather than aria-errormessage.
Assistive technology supports aria-describedby far more widely than aria-errormessage. When an empty required field references its message only with aria-errormessage, many screen reader users hear the field with no mention of what's missing.
Reference the message with aria-describedby instead.
Severity: Serious
Explains a blocked submission
Reported as: No accessible error notification
When an empty required text input stops a submission, the field must be associated with a visible message saying what's missing.
When nothing appears, or a message appears at the top of the page with nothing tying it to the field, screen reader users submit and hear nothing. They may conclude the button is broken, or that the form went through, and leave believing they've finished.
Show a message naming the missing entry, reference it from the field with aria-describedby, and move focus to the field. When several fields are empty, focus the first and give each field its own message.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 3.3.1 Error Identification (A) | If an input error is automatically detected, the item that is in error is identified and the error is described to the user in text. |
| EN 301 549 | 9.3.3.1 Error Identification | Same as the WCAG text. |
| Section 508 | 1194.21(l) | When electronic forms are used, the form shall allow people using assistive technology to access the information, field elements, and functionality required for completion and submission of the form, including all directions and cues. |
| Section 508 | 1194.22(n) | When electronic forms are designed to be completed on-line, the form shall allow people using assistive technology to access the information, field elements, and functionality required for completion and submission of the form, including all directions and cues. |
Flags the field that failed
Reported as: aria-invalid did not update
Once a submission has been attempted, a required text input that's still empty or holds an invalid entry must report itself invalid.
When a submission fails and the text input doesn't declare aria-invalid, users can't tell which field held up the form without checking each one.
Set aria-invalid="true" on required fields that are empty or hold an invalid entry when the user tries to submit. Remove aria-invalid or set it to false once the input is valid.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
FAQ
Which WCAG success criteria do the text input issues relate to?
The largest group relates to 4.1.2 Name, Role, Value: the textbox role, declaring the disabled state one way, nested interactive elements, and reporting the invalid state. The accessible name, the required state, and ignoring typing while read-only or disabled relate to 1.3.1 Info and Relationships.
Reaching the text input, taking focus on the element with the role, typing into its value, and inserting line breaks relate to 2.1.1 Keyboard. Keeping context as the value changes relates to 3.2.2 On Input, and explaining a rejected entry or a blocked submission relates to 3.3.1 Error Identification.
Referencing the error message with aria-describedby, enforcing a custom input's constraints in code, and keeping a disabled text input out of the tab order map to no WCAG success criterion and are best practices.
Why are some text input issues marked as Critical and others as Minor?
Severity reflects how much an issue gets in users' way. Critical issues stop users outright:
- A text input with no role
- A text input with no accessible name
- A text input keyboard users can't reach or type into
- A rejected entry with no message saying what was wrong
Serious issues confuse users though tasks are still possible:
- A required text input that doesn't say so
- A wrong or unsupported disabled state
- A button or other control nested inside the field
- A change of context while users type
- An error message referenced only with
aria-errormessage - Constraint attributes a custom text input doesn't enforce
- A blocked submission with no message on the empty field
Moderate issues make the field harder to use:
- A read-only or disabled text input that still accepts typing
- A multiline text input with no key that breaks the line
- An invalid state that doesn't update
Minor issues are smaller obstacles:
- A disabled text input in the tab order
- Focus on an element other than the one with the role
The aria-owns check and the check on where the role sits carry no severity: Evinced reports them as general and sanity checks.
Related Patterns
- Combobox: a text field paired with a popup of values to choose from
- Listbox: a choice from a list of options
- Radio Group: a single choice from a short list of named options
- Checkbox: an option users check or uncheck