menengahdomkeamananMenengah3 mnt baca

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">):

javascript
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 TEBAL

textContent 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: mirip textContent tapi "sadar CSS": ia mengabaikan teks di elemen yang display: none dan 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.

javascript
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:

javascript
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:

javascript
// AMAN: tampil sebagai teks, tidak dieksekusi
document.getElementById("aman").textContent = komentarUser;

Contoh realistis kedua: kolom komentar yang aman.

javascript
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 meledak

Membaca vs Menulis

Ketiga properti juga bisa MEMBACA konten:

javascript
el.textContent; // semua teks, termasuk yang tersembunyi CSS
el.innerText;   // teks yang TERLIHAT saja (lebih lambat)
el.innerHTML;   // string HTML mentah di dalamnya

Untuk mengambil teks biasa, textContent lebih cepat dan konsisten lintas browser.

Jebakan Umum

  • Memakai innerHTML untuk data user "karena lebih gampang". Ini sumber XSS nomor satu di aplikasi pemula.
  • Mengira innerText sama persis dengan textContent. Beda: innerText memicu reflow dan hasilnya tergantung CSS yang sedang berlaku.
  • Men-set innerHTML berulang 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.

Live Playground
export default function App(): JSX.Element {
  return <h1>Hello world</h1>
}

Edit kode di kiri, preview kanan ter-update otomatis.

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>