aria-readonlyaria-readonly indicates that a widget's value cannot be edited, but the widget itself is still fully operable, focusable, selectable, and copyable, unlike a disabled control. It is the ARIA equivalent of the native readonly attribute, for use on custom widgets that don't have a native readonly state of their own.
readonly, for comparisonA native input's own readonly attribute needs no ARIA at all, it's mapped to the accessibility tree automatically.
Expected result: the field should be announced as read-only. It should remain focusable, and its value should be selectable and copyable, but not editable.
<input type="text" value="ABC-123-XYZ" readonly>
aria-readonly on a custom widgetThis is a custom text field, built from a contenteditable element with role="textbox" rather than a native input. Since it has no native readonly attribute to rely on, aria-readonly is what communicates the same state.
Expected result: the field should be announced as read-only, the same as Example 1. It should remain focusable.
<div
role="textbox"
aria-labelledby="custom-readonly-label"
aria-readonly="true"
contenteditable="false"
tabindex="0"
>ABC-123-XYZ</div>
Readonly is not the same as disabled. A read-only field stays focusable, its value can still be selected and copied, and for native form fields, it's still submitted with the form. A disabled field is removed from the tab order, its value typically cannot be selected, and it is excluded from form submission entirely. If a value should still be readable and copyable, but not editable, readonly is usually the correct choice, not disabled.
Note for testing: confirm with your standard browser and screen reader combinations that both examples are announced as read-only, and that the distinction from a disabled field (still focusable, still selectable) actually holds in practice.