Pernah kebayang nulis HTML di dalam JavaScript? Awalnya kedengeran aneh — kayak nuangin teh ke gelas yang lagi isi kopi. Tapi pas dicoba, kamu ngerti kenapa tim React ngerancang ini: deketin markup sama logika yang ngehasilin markup itu. Variabel, kondisi, dan UI hidup di file yang sama, gak loncat-loncat antar file. Itulah JSX (JavaScript XML) — syntax extension yang bikin kamu nulis HTML-like di dalam JavaScript, terus Babel translate jadi JS biasa pas build.
🤔 Bukan HTML murni. JSX kelihatan kayak HTML tapi BEDA di beberapa detail penting (
class→className,for→htmlFor, camelCase event). Kenapa? Karena HTML attribute names konflik dengan reserved JavaScript keywords. Detail kecil yang sering bikin pemula bingung: "lho kok class gak jalan?".
Aturan JSX
- Satu root element — return harus dibungkus dalam satu elemen (atau Fragment
<>...</>) - Self-closing tags —
<img />,<br />,<input />(HTML boleh<br>, JSX wajib/) className, bukanclass— gunakanclassNameuntuk CSS class (classadalah JS keyword)- Kurung kurawal
{}— untuk nyelipin ekspresi JavaScript
function App() {
const nama = "Budi"
const tahun = 2026
return (
<div>
<h1>Halo, {nama}!</h1>
<p>Tahun ini {tahun}</p>
<p>2 + 3 = {2 + 3}</p>
<p>{tahun >= 2024 ? "Era AI" : "Pra-AI"}</p>
</div>
)
}
Ekspresi di dalam {} bisa berupa variabel, operasi matematika, pemanggilan fungsi, atau ternary operator. Statement (if/for/let) gak bisa langsung — pakai expression saja.
🎭 Analogi sehari-hari
JSX itu kayak template undangan kawinan digital. Format dasarnya HTML (cantik, terstruktur), tapi ada slot kosong {nama_tamu}, {tanggal_acara}, {lokasi_resepsi} yang otomatis kepenuhan dari database tamu undangan. JavaScript variable + ekspresi nempel langsung di markup — pas browser render, slot-slot tadi di-replace sama nilai aktual. Lebih readable dari nge-concat string di JS murni ("Halo, " + nama + "!" ribet pas teks panjang), lebih powerful dari template engine biasa karena kamu bisa run kode JavaScript penuh di slot.
⚠️ Jebakan yang sering ditemui
class→className—classkeyword di JavaScript (class Foo {}). React pakaiclassName. Lupa = warning di console + CSS gak nempel.for→htmlFor— sama alasannya,forkeyword loop JS.<label htmlFor="email">.- CSS property camelCase di inline style —
<div style={{ backgroundColor: "red" }}>(BUKANbackground-color). Inline style itu JS object, bukan string CSS. - Lupa balikin (return) JSX —
function App() { <h1>Halo</h1> }(gak ada return) = component render kosong. Wajibreturnatau implicit return di arrow() => <h1>...</h1>. - Multiple root elements = error. Bungkus dalam
<>...</>(Fragment) atau<div>. {}ngira buat object literal —return ({ x: 1 })salah artinya. Buat object:return ({ x: 1 })bingungin parser. JSX butuh tag, bukan object.- Comment di JSX —
// pakai //gak jalan di tengah JSX. Pakai{/* comment */}.
🧪 Tebakan cepat — hasil render apa? Tanpa run, tebak hasil:
const nama = "" // string kosong const items = [1, 2, 3] return ( <div> <p>{nama || "Anonim"}</p> <p>{items.length && "Ada item"}</p> <p>{items.map(n => <span key={n}>{n} </span>)}</p> </div> )Jawaban:
<p>Anonim</p>,<p>3</p>(BUKAN "Ada item" —items.lengthtruthy =3, jadi React render angka 3!),<p><span>1 </span><span>2 </span><span>3 </span></p>. Pelajaran: hati-hati&&dengan number —0falsy = render "0" di layar (bukan kosong!). Pakai ternaryx > 0 ? "..." : nulllebih aman.
TL;DR: JSX = HTML-like syntax di dalam JavaScript, dikompilasi Babel jadi React.createElement(). Aturan: 1 root element, self-close tag, className (bukan class), htmlFor (bukan for), {ekspresi JS} di slot. CSS inline pakai object camelCase. Awas {cond && "..."} dengan number — render "0" kalau cond=0. Comment pakai {/* ... */}. Multiple element? Bungkus Fragment <>...</>.