Атрибут HTML contenteditable
Атрибут contenteditable определяет, можно ли редактировать содержимое элемента. Значения, работа с JavaScript и советы по доступности.
Атрибут HTML contenteditable указывает, можно ли редактировать содержимое элемента непосредственно в браузере. Если его включить, пользователь сможет кликнуть внутри элемента и вводить, удалять и форматировать текст — как в текстовом редакторе — без <input> или <textarea>.
Поскольку атрибут работает практически с любым элементом, contenteditable может превратить <div>, <p> или целый раздел в область редактирования. Он входит в состав глобальных атрибутов и доступен для любого HTML-элемента.
Когда использовать contenteditable
contenteditable — это основа встроенного редактирования. Вы встретите его в:
- Редакторах форматированного текста (блоки «WYSIWYG» в CMS, почтовых клиентах и формах комментариев). В отличие от
<textarea>, редактируемый элемент может содержать настоящий HTML — жирный текст, ссылки, списки и изображения — и пользователь видит форматированный результат прямо в процессе набора. - Встроенном редактировании — когда пользователь кликает на заголовок или ячейку таблицы, чтобы переименовать её на месте, не открывая отдельную форму.
- Интерфейсах предварительного просмотра и заметок, где область редактирования является отображаемым результатом.
Используйте <textarea> или <input>, если вам нужен только простой текст, который отправляется с формой: это настоящие поля формы, они поддерживают валидацию и автоматически передают своё значение. Прибегайте к contenteditable, когда нужен форматированный (HTML) контент или когда редактирование должно происходить внутри существующей разметки страницы.
Синтаксис
<tag contenteditable="true">...</tag>Атрибут принимает следующие значения:
| Значение | Описание |
|---|---|
true (или "") | Элемент доступен для редактирования. Пустая строка работает так же, как true. |
false | Элемент недоступен для редактирования. |
inherit | Элемент наследует состояние редактирования от ближайшего родителя. Это также значение по умолчанию, если атрибут не указан. |
plaintext-only | Элемент доступен для редактирования, но форматирование отключено — принимается только простой текст. Поддерживается современными браузерами, но перед использованием проверьте поддержку. |
Пример
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<p contenteditable="false">
This is a paragraph. It is not editable.
</p>
<p contenteditable="true">
This is a paragraph. It is editable. Try to change this text.
</p>
</body>
</html>Наследование со значением inherit
Если contenteditable не задан для дочернего элемента, он наследует состояние редактирования от родителя. Можно сделать всю область редактируемой на уровне родителя, а затем отдельный дочерний элемент отключить с помощью contenteditable="false":
<!DOCTYPE html>
<html>
<head>
<title>contenteditable inherit example</title>
</head>
<body>
<div contenteditable="true">
<p>This paragraph inherits editing from the div, so you can change it.</p>
<p contenteditable="false">
This paragraph opts out — it is locked and cannot be edited.
</p>
<p contenteditable="inherit">
This one explicitly inherits, so it is editable again.
</p>
</div>
</body>
</html>Чтение и сохранение отредактированного содержимого с помощью JavaScript
Элемент с contenteditable — это не поле формы, поэтому его значение не отправляется вместе с формой и у него нет свойства value. Вместо этого содержимое читается непосредственно из элемента:
element.innerHTML— отредактированное содержимое в виде HTML (сохраняет жирный текст, ссылки, списки).element.textContent— отредактированное содержимое в виде простого текста (форматирование убирается).
Чтобы реагировать на правки в реальном времени, следует прослушивать событие input, которое срабатывает при каждом изменении:
<!DOCTYPE html>
<html>
<head>
<title>Save editable content</title>
</head>
<body>
<div id="editor" contenteditable="true">
Edit me, then reload the page.
</div>
<script>
const editor = document.getElementById("editor");
// Restore any previously saved content.
const saved = localStorage.getItem("note");
if (saved !== null) {
editor.innerHTML = saved;
}
// Save on every edit.
editor.addEventListener("input", () => {
localStorage.setItem("note", editor.innerHTML);
// In a real app you would debounce this and POST it to a server, e.g.
// fetch("/api/save", { method: "POST", body: editor.innerHTML });
});
</script>
</body>
</html>Сохранение innerHTML напрямую на сервер означает хранение сырого HTML. Всегда санируйте ненадёжный HTML на сервере (или с помощью проверенной клиентской библиотеки) перед сохранением или повторным отображением, чтобы предотвратить межсайтовый скриптинг (XSS).
Доступность
Обычный элемент с contenteditable выглядит редактируемым, но, в отличие от настоящего поля формы, он не предоставляет никакой семантики поля для вспомогательных технологий — экранные читалки могут не объявить его как элемент, в который можно вводить текст. При создании пользовательского редактора помогите им:
- Добавьте
role="textbox", чтобы элемент объявлялся как редактируемое текстовое поле. Добавьтеaria-multiline="true", если поле принимает несколько строк. - Добавьте
aria-label(или свяжите видимый<label>черезaria-labelledby), чтобы у поля было доступное имя. - Добавьте
tabindex="0", если элемент не получает фокус по умолчанию, чтобы пользователи клавиатуры могли до него добраться.
<div
contenteditable="true"
role="textbox"
aria-multiline="true"
aria-label="Comment"
tabindex="0"
>
Type your comment…
</div>Несоответствия между браузерами
contenteditable — мощный инструмент, однако его поведение не одинаково в разных браузерах. Именно поэтому в продакшн-приложениях обычно используют библиотеку (или значение plaintext-only), а не сырой contenteditable:
- Поведение клавиши Enter различается. Нажатие Enter может обернуть новую строку в
<div>,<p>или вставить<br>, в зависимости от браузера. Не рассчитывайте на конкретную структуру сгенерированного HTML. - Вставка зачастую привносит стили и теги из источника; возможно, потребуется перехватить событие
pasteи очистить содержимое. plaintext-onlyотключает форматирование, но поддерживается не везде — перед использованием проверяйте поддержку методом обнаружения функциональности.
Связанные атрибуты
spellcheck— включает или отключает проверку орфографии в браузере внутри редактируемой области.draggable— управляет возможностью перетаскивания элемента.- Глобальные атрибуты — полный набор атрибутов, применимых к любому элементу.