Усі три властивості читають і записують вміст елемента, але різними способами.
textContent - сирий текст усіх вузлів-нащадків, як він є в DOM:
- повертає текст прихованих елементів (
display: none), вміст<script>і<style>; - зберігає пробіли й переноси рядків з розмітки;
- не викликає перерахунку стилів - швидкий;
- при записі вставляє текст, а не розмітку:
<b>стане видимими символами.
innerText - текст як його бачить користувач:
- враховує CSS: приховані елементи не потрапляють у результат,
text-transform: uppercaseзмінює регістр, блокові елементи дають переноси рядків; - для цього браузер мусить розрахувати розкладку (layout). Читання
innerTextу циклі - джерело примусових перерахунків і повільної сторінки; - при записі теж вставляє текст, але перетворює
\nна<br>.
innerHTML - розмітка як рядок HTML:
- при читанні - серіалізований HTML нащадків;
- при записі - розбирає рядок як HTML, видаляючи старих нащадків разом з їхніми обробниками подій.
const name = '<img src=x onerror="stealCookies()">';
title.textContent = name; // безпечно: показується як текст
title.innerHTML = name; // XSS: виконається onerror
Що обирати:
| Задача | Властивість |
|---|---|
| вивести дані користувача чи API | textContent |
| прочитати текст для копіювання так, як його бачать | innerText |
| вставити довірену розмітку з власного шаблону | innerHTML (або краще createElement / <template>) |
Для запису тексту за замовчуванням - textContent: він швидший і безпечний. Це той самий принцип, що й {{ }} у Blade, який екранує HTML, на відміну від {!! !!}.
Ще варіанти: element.append('текст') теж додає текст безпечно; insertAdjacentHTML('beforeend', html) вставляє розмітку, не руйнуючи наявних нащадків (але так само небезпечний для недовірених даних).
value для полів форми: вміст <input> і <textarea> - це властивість value, а не textContent.