DOM: innerHTML vs textContent
Tiga cara mengisi konten elemen (textContent, innerHTML, innerText), kapan memakai masing-masing, dan bahaya XSS: kenapa data dari user tidak boleh masuk ke innerHTML tanpa sanitasi.
Kenapa Ada Tiga Cara?
Mengisi konten elemen adalah operasi DOM paling sering: menampilkan nama user, hasil pencarian, pesan error. JavaScript menyediakan tiga properti yang kelihatannya mirip tapi perilakunya beda jauh: textContent, innerHTML, dan innerText. Salah pilih bisa berarti tampilan rusak, atau lebih parah, lubang keamanan.
Contoh sederhana memakai playground modul ini (ada <div id="aman"> dan <div id="html">):
const aman = document.getElementById("aman");
const html = document.getElementById("html");
aman.textContent = "<b>Halo</b>";
console.log(aman.textContent); // "<b>Halo</b>", tampil APA ADANYA
html.innerHTML = "<b>Halo</b>";
console.log(html.innerHTML); // "<b>Halo</b>", dirender TEBALtextContent memperlakukan semuanya sebagai teks polos. innerHTML mem-parse string sebagai HTML sungguhan.
Kapan Pakai Mana?
Aturannya sederhana dan wajib dihafal:
textContent: untuk teks murni, terutama DATA DARI USER atau API. AMAN karena tidak pernah dirender sebagai HTML.innerHTML: untuk template HTML yang KAMU tulis dan kontrol penuh. Cepat dan praktis untuk render list.innerText: miriptextContenttapi "sadar CSS": ia mengabaikan teks di elemen yangdisplay: nonedan memperhitungkan line break visual. Lebih lambat karena memicu perhitungan layout.
Contoh realistis: render daftar notifikasi dari template yang kamu kontrol, tapi nama pengirim tetap via textContent.
const notifikasi = [
{ dari: "Ani", pesan: "mengirimimu pesan" },
{ dari: "Budi", pesan: "menyukai fotomu" },
];
const wadah = document.getElementById("html");
wadah.innerHTML = notifikasi
.map(n => `<li><strong></strong> <span></span></li>`)
.join("");
// isi teks user dengan textContent agar aman
wadah.querySelectorAll("li").forEach((li, i) => {
li.querySelector("strong").textContent = notifikasi[i].dari;
li.querySelector("span").textContent = notifikasi[i].pesan;
});Ini pola hybrid yang dipakai aplikasi produksi: struktur via innerHTML (cepat), data user via textContent (aman).
Bahaya XSS: Serangan Paling Klasik Web
XSS (Cross-Site Scripting) terjadi saat data user dirender sebagai HTML tanpa sanitasi. Perhatikan:
const komentarUser = '<img src=x onerror="curiCookie()">';
document.getElementById("html").innerHTML = komentarUser;
// Browser MENGEKSEKUSI onerror! Fungsi jahat berjalan.Penyerang tidak butuh tag <script>; atribut event seperti onerror, onload, atau onclick di tag apa pun sudah cukup. Sekali masuk, script jahat bisa mencuri cookie, membajak sesi, atau menampilkan form phishing. Versi amannya:
// AMAN: tampil sebagai teks, tidak dieksekusi
document.getElementById("aman").textContent = komentarUser;Contoh realistis kedua: kolom komentar yang aman.
function tambahKomentar(nama, isi) {
const li = document.createElement("li");
const namaEl = document.createElement("strong");
namaEl.textContent = nama; // aman walau nama berisi tag HTML
const isiEl = document.createElement("p");
isiEl.textContent = isi; // aman
li.append(namaEl, isiEl);
document.getElementById("daftar-komentar").appendChild(li);
}
tambahKomentar("Hacker", '<img src=x onerror="jahat()">');
// tampil apa adanya sebagai teks, tidak meledakMembaca vs Menulis
Ketiga properti juga bisa MEMBACA konten:
el.textContent; // semua teks, termasuk yang tersembunyi CSS
el.innerText; // teks yang TERLIHAT saja (lebih lambat)
el.innerHTML; // string HTML mentah di dalamnyaUntuk mengambil teks biasa, textContent lebih cepat dan konsisten lintas browser.
Jebakan Umum
- Memakai
innerHTMLuntuk data user "karena lebih gampang". Ini sumber XSS nomor satu di aplikasi pemula. - Mengira
innerTextsama persis dengantextContent. Beda:innerTextmemicu reflow dan hasilnya tergantung CSS yang sedang berlaku. - Men-set
innerHTMLberulang dalam loop untuk list besar: tiap set mem-parse ulang HTML. Bangun satu string dulu, set sekali di akhir. - Lupa bahwa
innerHTML += ...menghancurkan dan membangun ulang SEMUA anak elemen, termasuk menghapus event listener yang sudah terpasang.
Ringkasan
textContent untuk teks (aman, cepat), innerHTML untuk template HTML yang kamu kontrol penuh (cepat untuk render massal), innerText untuk teks yang terlihat saja (lambat, jarang dibutuhkan). Aturan emas keamanan: data dari user atau sumber luar TIDAK PERNAH masuk innerHTML tanpa sanitasi. Satu baris ceroboh bisa menjadi pintu masuk pencurian sesi.
export default function App(): JSX.Element { return <h1>Hello world</h1> }
Tantangan
Render Aman
Diberi komentar = '<img src=x onerror="jahat()"> Halo!'. Tampilkan di #aman dengan textContent (aman), lalu jelaskan di console kenapa innerHTML berbahaya di sini. Memahami perbedaan ini adalah syarat mutlak sebelum membangun fitur komentar, review produk, atau chat: semua aplikasi nyata yang menampilkan input user wajib lolos dari jebakan XSS.
<!doctype html> <html> <head> <meta charset="utf-8" /> </head> <body> <h1>Halo JS</h1> <p>Buka console preview untuk melihat output.</p> <script src="index.js"></script> </body> </html>