Standards · ARIA

State Widget state

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-readonly on a native <input> while also using the HTML readonly attribute. The native attribute is enough; the duplicate can drift.
  • Using aria-readonly on a non-form element like a <p> or <div> — the state has no meaning there.
  • Setting aria-readonly="true" and aria-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>