aria-readonly
Indicates that a form control's value cannot be edited but the control is still operable — focusable, copyable, and submitted with the form. Different from aria-disabled, which makes the control inoperable.
When to use
On a form control whose value the user can see and copy but cannot change — an order summary line that the user shouldn’t edit, a reviewer’s comment in a multi-step approval, a generated identifier. The user can still tab to it, select its text, and read it; the form will still submit its value.
If you are using <input>, <textarea>, or <select>, the HTML readonly attribute handles all of this natively and is preferred. Reach for aria-readonly on custom widgets: role="combobox", role="grid", role="listbox", role="slider", role="spinbutton", and role="textbox" (custom).
Compared with related states:
aria-readonly— focusable, value visible and copyable, value submitted, value cannot change.aria-disabled— focusable (stays in the tab order) but does not respond to input, and conventionally not submitted.- HTML
disabled— removed from the tab order entirely, ignored, not submitted. aria-hidden— removed from the accessibility tree; this is a different goal.
The choice between read-only and disabled is semantic: read-only means “valid value you can see”, disabled means “don’t bother with this right now”.
How to keep it in sync
Valid values are "true" and "false". Default to "false" (or omit) on editable controls; switch to "true" when the field becomes read-only.
When aria-readonly="true":
- The control must remain focusable. Do not also set
tabindex="-1". - Click/keyboard handlers should not mutate the value. Selecting and copying text must still work.
- Style the field so the read-only appearance is visually distinct from an editable one — usually a different background, no caret, no hover affordance.
Common failures
- Setting
aria-readonlyon a native<input>while also using the HTMLreadonlyattribute. The native attribute is enough; the duplicate can drift. - Using
aria-readonlyon a non-form element like a<p>or<div>— the state has no meaning there. - Setting
aria-readonly="true"andaria-disabled="true"simultaneously. Pick one based on whether the field is “valid but locked” or “ignore for now”. - Making a read-only field unfocusable (with
tabindex="-1") — screen-reader users can no longer reach it to read the value. - Hiding the read-only field visually but keeping it in the tab order.
Example
<label for="order-id">Order ID</label>
<input
id="order-id"
type="text"
value="ORD-83472"
readonly
>
<!-- Custom widget where the native attribute isn't available -->
<div
role="textbox"
tabindex="0"
aria-readonly="true"
aria-label="Generated reference"
>
ORD-83472
</div>