Атрибут readonly (по-русски «только для чтения») запрещает посетителю менять значение поля, но поле остаётся рабочим: в него можно встать курсором, выделить текст и скопировать его, а при отправке формы значение уйдёт на сервер. Прописывают readonly в тегах <input> и <textarea>. Он булевый: достаточно самого слова в открывающем теге.
В этой статье
- Атрибут readonly в HTML: что это и для чего нужен
- Как записать атрибут readonly: какие у него бывают значения
- Для каких тегов и типов input работает readonly
- Чем readonly отличается от disabled: фокус, отправка и вид
- Как readonly влияет на проверку полей: required и pattern
- Стиль readonly: селекторы [readonly], :read-only и :read-write
- Как установить readonly через JavaScript и jQuery
- Что делать, если readonly не работает: checkbox, radio, file и select
- Readonly не защищает данные: проверка на сервере
- Частые ошибки с атрибутом readonly
- Шпаргалка по атрибуту readonly
Атрибут readonly в HTML: что это и для чего нужен
Слово readonly складывается из read («читать») и only («только»). Атрибут нужен там, где значение поля важно показать, но менять его посетителю нельзя: номер заказа, цена, адрес, сформированный скриптом, или условия, с которыми человек соглашается.
<input value="Одесса" readonly>
<textarea readonly>Текст, который нельзя изменить</textarea>
Введите букву в оба поля: первое меняется, второе нет. В нижней строке видно, что поле readonly совпадает с селектором :read-only.
Поле readonly не выглядит особенным: рамка и цвет текста такие же, как у обычного. Отличить его можно только по поведению, поэтому обычно такие поля оформляют отдельно, как показано в разделе про стили.
Как записать атрибут readonly: какие у него бывают значения
Любая из записей ниже включает режим «только для чтения». Если слово readonly есть в теге, браузер не смотрит на значение: в стандарте для булевых атрибутов важно только присутствие.
<input value="Одесса" readonly>
<input value="Одесса" readonly="readonly">
<input value="Одесса" readonly="false">
<input value="Одесса">
У первых трёх полей свойство readOnly равно true, включая запись readonly="false". Выключает режим только полное отсутствие атрибута.
Запись readonly="false" ничего не отключает, это частая ошибка. Чтобы разрешить ввод, атрибут нужно убрать из тега целиком. Запись readonly="readonly" нужна для XHTML и в обычной верстке избыточна.
Для каких тегов и типов input работает readonly
По стандарту readonly работает у <input> с текстовыми типами и датами, а также у <textarea>. Для остальных значений type атрибут не предусмотрен: браузер его не отвергает, но защиты от изменения не даёт. Выберите тип в демонстрации и попробуйте изменить поле.
<input type="text" value="Odesa" readonly>
<input type="checkbox" checked readonly>
У text, search, url, tel, email, password, number, date, time и month поле не меняется. У range и checkbox значение меняется, хотя селектор :read-only совпадает.
| Где прописан readonly | Защищает от изменения | Что делать, если нужна защита |
|---|---|---|
text, search, url, tel, email, password | Да | Ничего, атрибут работает |
number, date, time, month, week, datetime-local | Да | Ничего, атрибут работает |
<textarea> | Да | Ничего, атрибут работает |
checkbox, radio, range | Нет, значение меняется | disabled и скрытое поле, или блокировка клика скриптом |
color, file, hidden, кнопки | Не предусмотрено стандартом | disabled |
<select> | Нет, у списка такого атрибута нет | disabled и скрытое поле, либо вывести значение текстом |
Подробнее о значениях type рассказано на странице атрибута type, а об устройстве полей в уроке «Поля ввода: input и его типы ».
Чем readonly отличается от disabled: фокус, отправка и вид
Оба атрибута мешают посетителю менять значение, но поведение у них разное. Поле readonly остаётся частью формы: оно получает фокус и отправляется. Поле disabled полностью выключено: фокус его обходит, а на сервер оно не попадает.
<form>
<input name="a" value="A">
<input name="b" value="B" readonly>
<input name="c" value="C" disabled>
<button type="submit">Отправить</button>
</form>
Нажмите кнопку: на сервер ушли a и b, поле c отсутствует. Нажимайте Tab: в журнале фокуса есть поле b и нет поля c.
| Признак | readonly | disabled |
|---|---|---|
| Фокус по клику и по клавише Tab | Есть | Нет |
| Выделить и скопировать текст | Можно | Зависит от браузера |
| Уходит на сервер | Да | Нет |
| Проверка required и pattern | Не проверяется | Не проверяется |
| Вид по умолчанию | Как у обычного поля | Серый текст и фон, курсор-стрелка |
| Совпадает с :read-only | Да | Да |
Выбирайте по задаче. Если значение должно дойти до сервера, берите readonly. Если поле нужно временно выключить, например пока не выбран другой вариант, берите disabled.
Как readonly влияет на проверку полей: required и pattern
Поле readonly не проходит встроенную проверку: браузер считает, что посетитель не может его исправить, и пропускает. Поэтому required, pattern и другие ограничения у такого поля не срабатывают, даже когда значение им не соответствует.
<input id="e" required readonly>
<input id="g" pattern="[0-9]+" value="abc" readonly>
<script>
console.log(e.willValidate); // false
console.log(e.checkValidity()); // true
</script>
Нажмите кнопку: у readonly-полей willValidate равно false, а checkValidity() даёт true, хотя они пустые или не подходят под шаблон. Обычное поле с required не проходит.
Отсюда практический вывод: required вместе с readonly бессмысленно. Если пустое значение недопустимо, заполните поле на сервере или скриптом ещё до показа. О проверке полей подробно рассказано в уроке «Встроенная валидация форм ».
Стиль readonly: селекторы [readonly], :read-only и :read-write
Для оформления есть три способа. Селектор input[readonly] выбирает поля, у которых атрибут есть. Псевдокласс :read-only совпадает с полями, которые посетитель не может изменить, а :read-write с теми, которые может.
input:read-only {
background: #ece7dd;
border-style: dashed;
}
input:read-write:focus {
outline: 2px solid #2f6fde;
}
Серую пунктирную рамку получили и поле readonly, и поле disabled. В нижней строке видно, как совпадают оба псевдокласса.
У :read-only есть подвох: :read-only совпадает и с полями disabled, и с обычными блоками вроде <div> без редактирования. Чтобы выбрать только поля readonly, пишите input[readonly] или input:read-only:not(:disabled). Селектор [readonly="readonly"] с полным значением не совпадёт с записью без значения.
Как установить readonly через JavaScript и jQuery
Включить и выключить readonly скрипт может через свойство readOnly. Название пишется с заглавной буквой в середине: свойство с маленькой буквы не работает и просто создаёт лишнее поле объекта. Ещё можно управлять атрибутом: setAttribute('readonly', ''), removeAttribute('readonly') и toggleAttribute('readonly').
const input = document.querySelector('input');
input.readOnly = true; // включить
input.readOnly = false; // выключить
input.toggleAttribute('readonly');
input.setAttribute('readonly', 'false'); // всё равно включено
input.readonly = true; // ошибка: ничего не изменится
Нажмите вторую кнопку, чтобы выключить режим. Затем нажмите четвёртую: свойство с маленькой буквы ничего не меняет. А третья кнопка включает режим, хотя в значении написано false.
Если на сайте подключён jQuery, привычнее писать через методы. Для булевых значений с версии 1.6 рекомендуют prop(), потому что он работает со свойством, а attr() со строкой атрибута.
$('#city').prop('readonly', true); // включить
$('#city').prop('readonly', false); // выключить
$('#city').attr('readonly', 'readonly'); // включить через атрибут
$('#city').removeAttr('readonly'); // выключить
Результат у обоих вариантов одинаковый. Если задача решается без библиотеки, достаточно input.readOnly = true.
Что делать, если readonly не работает: checkbox, radio, file и select
У флажков, переключателей и списков readonly не защищает значение, потому что для них стандарт этот атрибут не предусматривает. Флажок с readonly переключается как обычно. Для поля type="file" атрибут тоже не работает: файл выбирают через отдельный диалог, и запретить выбор можно только через disabled.
Если значение флажка должно уйти на сервер, но менять его нельзя, есть два способа. Первый: добавить disabled и продублировать значение скрытым полем. Второй: взять обычный флажок и отменить клик скриптом.
<input type="checkbox" checked disabled>
<input type="hidden" name="agree" value="on">
<input type="checkbox" name="agree" value="on" checked id="lock">
<script>
lock.addEventListener('click', e => e.preventDefault());
</script>
Щёлкните по каждому флажку и нажмите кнопку. Флажок readonly снялся, а в отправку не попал. Disabled не отправляется вообще. Заблокированный остался отмеченным и ушёл.
Для списка <select> действует та же схема: disabled и скрытое поле с выбранным значением. Если выбор вообще не нужен, значение проще вывести обычным текстом.
Readonly не защищает данные: проверка на сервере
Атрибут работает только в браузере посетителя, а управлять этим браузером вы не можете. Любой человек может открыть инструменты разработчика, удалить readonly и ввести другое значение. Для сервера такая форма неотличима от настоящей.
<form>
<input name="price" value="100" readonly>
</form>
<script>
// то же самое делает посетитель в консоли
price.removeAttribute('readonly');
</script>
Нажмите первую кнопку, измените число и отправьте форму: на сервер уходит уже изменённая цена.
Поэтому поля, которые нельзя менять, нужно проверять на сервере: цену, номер заказа и другие значения брать из своей базы, а присланным полям не доверять. Атрибут readonly удобен для посетителя, а не для безопасности.
Частые ошибки с атрибутом readonly
Почти все ошибки с readonly сводятся к ожиданию, что атрибут блокирует поле целиком или защищает данные. В таблице собраны такие записи и то, к чему они приводят.
| Запись | Что получится | Как правильно |
|---|---|---|
<input type="checkbox" readonly> | Флажок переключается как обычно | disabled и скрытое поле или блокировка клика |
<select readonly> | Список меняется, атрибут не работает | disabled и скрытое поле |
readonly="false" | Поле остаётся только для чтения | Убрать атрибут целиком |
input.readonly = true | Ничего не происходит, свойство пишется с заглавной буквой | input.readOnly = true |
<input disabled>, когда значение нужно серверу | Поле на сервер не попадает | Использовать readonly |
<input required readonly> | Проверка required не срабатывает | Задать значение заранее, не полагаться на required |
| readonly как защита цены или номера заказа | Посетитель убирает атрибут в консоли и отправляет своё | Проверять значение на сервере |
setAttribute('readonly', 'false') | Режим остаётся включённым | removeAttribute('readonly') или readOnly = false |
[readonly="readonly"] в CSS | Не совпадает с записью readonly без значения | [readonly] или :read-only |
input:read-only только для readonly-полей | Совпадает ещё с полями disabled | input[readonly] |
<input type="file" readonly> | Атрибут не предусмотрен для file | disabled |
Пустое поле readonly с placeholder | Подсказка видна, а ввести ничего нельзя | Выводить в value текст вроде «Нет данных» |
Шпаргалка по атрибуту readonly
Когда нужно быстро вспомнить запись, ищите задачу в левом столбце. Правый столбец ведёт на отдельную страницу справочника.
| Что нужно | Что прописать | Тег |
|---|---|---|
| Запретить менять текст в поле | <input value="Одесса" readonly> | <input> |
| Запретить менять многострочный текст | <textarea readonly>Текст</textarea> | <textarea> |
| Чтобы значение ушло на сервер | readonly | <input> |
| Выключить поле совсем | <input disabled> | <input> |
| Включить из JavaScript | input.readOnly = true | <input> |
| Выключить из JavaScript | input.readOnly = false | <input> |
| Включить через jQuery | $('#a').prop('readonly', true) | <input> |
| Оформить поля readonly | input[readonly] { ... } | <input> |
| Защитить флажок | <input type="checkbox" checked disabled> | <input> |