The HTML aria-readonly attribute
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
<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-readonlywidget 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?
When does aria-readonly fit better than aria-disabled?
Which wins when readonly and aria-readonly disagree?
Does aria-readonly lock a select menu?
Is aria-readonly allowed on a contenteditable element?
Why does an aria-readonly field look editable?
[aria-readonly=true] selector.






















