References

Beginner-friendly references for web development, with live, editable examples.

The HTML aria-readonly attribute

ARIA Accessibility
In short

The aria-readonly attribute states, for assistive technology, that a widget's value can be read and copied but not changed. The lock itself comes from the HTML readonly attribute on a text-entry <input> or a <textarea>, or from your own script on a custom widget.

Overview

The aria-readonly attribute says that the user can read a widget's value but not set it. The widget stays operable, unlike a disabled one. Typical cases are a form element that holds a constant, row or column headers in a spreadsheet grid, and a shopping cart total.

Chrome and Firefox disagree about <input aria-readonly="true">, which Chrome exposes as read-only and Firefox doesn't. Either way, the field still takes typed text, keeps its readOnly property false and matches :read-write.

Where HTML allows the readonly attribute, ARIA in HTML points you to it. Authors should not add aria-readonly="true" beside that attribute, and must not add aria-readonly="false". The ARIA version suits widgets HTML's attribute can't reach, such as a custom slider, listbox or grid.

Nine roles support it, namely checkbox, combobox, grid, gridcell, listbox, radiogroup, slider, spinbutton and textbox. The columnheader, rowheader, searchbox, switch and treegrid roles inherit it. It isn't a global attribute, so on other roles browsers must ignore it.

A grid passes the value down. Browsers must propagate aria-readonly from a grid to its gridcell elements, and a cell can override the value it gets. The value covers only whether cell content is editable, not whether the grid can be navigated or manipulated.

Syntax

<div role="grid" aria-label="Order" aria-readonly="true">
  <div role="row">
    <div role="gridcell">Blue mug</div>
    <div role="gridcell" tabindex="0" aria-readonly="false">2</div>
  </div>
</div>

Values

Value
true | false

Example

Live example
<p id="lab" style="margin:0 0 4px">Delivery note</p>
<div id="note" role="textbox" tabindex="0" contenteditable="true" aria-labelledby="lab" aria-multiline="true" aria-readonly="false" style="border:1px solid #767676;padding:6px;min-height:40px">Leave at the side door</div>
<p style="margin:8px 0"><button id="lock">Lock note</button></p>
<p id="out" role="status" style="overflow-wrap:anywhere"></p>
<p>Edit the note, press Lock note, then try to type in it again.</p>
<script>
const note = document.getElementById('note');
const lock = document.getElementById('lock');
const out = document.getElementById('out');
lock.addEventListener('click', function () {
  const locked = note.getAttribute('aria-readonly') === 'false';
  note.setAttribute('contenteditable', String(!locked));
  note.setAttribute('aria-readonly', String(locked));
  note.style.background = locked ? '#eee' : '';
  lock.textContent = locked ? 'Unlock note' : 'Lock note';
  out.textContent = locked
    ? 'Locked. The script turned contenteditable off and set aria-readonly to true.'
    : 'Unlocked. contenteditable is back on and aria-readonly is false.';
});
</script>

Best practices

  • Leave an aria-readonly widget reachable. Don't restrict navigation to it or its focusable descendants, and let people copy its value.
  • Keep aria-checked fixed on a role="checkbox" marked read-only, by making your click and Space handlers do nothing. The role supports aria-readonly, while the readonly attribute doesn't apply to a native checkbox.
  • In an editable grid, you can set aria-readonly="true" on each focusable gridcell that can't change, while the other cells stay editable.
  • Skip the attribute on a grid of links, such as a datepicker, where a value is unnecessary because leaving it out doesn't imply editable content.

Frequently asked questions

What does aria-readonly=true mean?
Setting aria-readonly=true means the user cannot change the element's value. The default, false, means the user can set it, apart from grids and gridcells, where a missing value doesn't imply editable content.
When does aria-readonly fit better than aria-disabled?
Use aria-readonly when the widget stays operable and its value stays relevant to the user. Choose aria-disabled when the element is unavailable for interaction.
Which wins when readonly and aria-readonly disagree?
HTML's readonly attribute overrides aria-readonly=false, and the field is exposed as read-only. It stays locked against typing as well.
Does aria-readonly lock a select menu?
No, a select with aria-readonly still lets the user pick another option. HTML has no readonly attribute for select either, so locking one takes disabled or your own script.
Is aria-readonly allowed on a contenteditable element?
Not with the value true, because ARIA in HTML forbids aria-readonly=true when isContentEditable is true. Typing still works there, so turn contenteditable off to lock the text.
Why does an aria-readonly field look editable?
The aria-readonly attribute has no default style, so an input with it looks like an editable one. Add your own cue with the [aria-readonly=true] selector.