Kenapa ini penting
Hampir setiap baris tampilan di React ditulis dengan JSX (JavaScript XML), sintaks yang terlihat seperti HTML tapi hidup di dalam file JavaScript. JSX membuat tampilan dan logika berada berdampingan, sehingga mudah dibaca: kamu bisa melihat struktur halaman sekaligus data yang mengisinya. Tapi karena JSX sebenarnya adalah JavaScript, ada beberapa aturan yang berbeda dari HTML biasa. Pemula sering terjebak di sini: menulis class alih-alih className, mengembalikan dua elemen tanpa pembungkus, atau bingung kenapa if tidak bisa ditulis di tengah markup. Kuasai aturannya sekarang, maka sisa perjalanan React jauh lebih mulus.
Konsep inti
JSX bukan HTML
Browser tidak mengerti JSX. Saat kamu menyimpan file, plugin React di Vite mengubah JSX menjadi panggilan fungsi JavaScript biasa yang menghasilkan objek elemen React. Karena itu, aturan JSX mengikuti aturan JavaScript.
Aturan 1: Satu elemen akar (root)
Sebuah komponen hanya boleh mengembalikan satu elemen paling luar. Alasannya sederhana: fungsi JavaScript hanya bisa me-return satu nilai. Kalau kamu butuh beberapa elemen sejajar tanpa menambah div yang tidak perlu, pakai Fragment: <>...</> (versi pendek) atau <Fragment>...</Fragment> (versi panjang, wajib jika butuh key).
Analogi: kurir hanya mau menerima satu paket. Kalau barangmu banyak, masukkan ke satu kardus. Fragment adalah kardus transparan: membungkus tapi tidak muncul di DOM.
Aturan 2: Semua tag harus ditutup
Di HTML, <img> dan <br> boleh tanpa penutup. Di JSX wajib ditutup: <img />, <br />, <input />.
Aturan 3: className dan atribut camelCase
Karena class adalah kata kunci di JavaScript, JSX memakai className. Begitu juga for pada label menjadi htmlFor. Atribut lain yang terdiri dari beberapa kata ditulis camelCase: onclick jadi onClick, tabindex jadi tabIndex, maxlength jadi maxLength. Pengecualian: atribut aria-* dan data-* tetap ditulis dengan tanda hubung.
| HTML | JSX |
|---|---|
class="kartu" |
className="kartu" |
for="email" |
htmlFor="email" |
onclick="..." |
onClick={...} |
style="color: red; font-size: 14px" |
style={{ color: 'red', fontSize: 14 }} |
<!-- komentar --> |
{/* komentar */} |
Aturan 4: Ekspresi JavaScript di dalam kurung kurawal {}
Kurung kurawal adalah "jendela" dari markup ke JavaScript. Di dalamnya kamu boleh menulis ekspresi (sesuatu yang menghasilkan nilai): variabel, operasi a + b, pemanggilan fungsi, ternary kondisi ? a : b, array.map(...). Kamu tidak boleh menulis pernyataan seperti if, for, atau deklarasi const di dalam {}. Logika seperti itu ditulis di atas return.
Kurung kurawal bisa dipakai di dua tempat: sebagai isi teks (<h1>{nama}</h1>) dan sebagai nilai atribut (<img src={urlFoto} />). Perhatikan: jangan diberi tanda kutip, karena src="{urlFoto}" akan dianggap teks literal.
Aturan 5: style menerima objek
Atribut style menerima objek JavaScript, bukan string. Itulah kenapa ada kurung kurawal ganda {{ }}: kurung luar adalah jendela JSX, kurung dalam adalah objek. Nama properti CSS juga camelCase: background-color menjadi backgroundColor. Angka tanpa satuan untuk properti seperti fontSize otomatis dianggap px.
Aturan 6: Nilai yang tidak dirender
true, false, null, dan undefined tidak menampilkan apa pun. Ini berguna untuk conditional rendering nanti. Tapi angka 0 tetap tampil, jebakan yang akan kita bahas di modul conditional rendering.
Keamanan: JSX meng-escape teks
Kalau kamu menaruh string berisi <script> di dalam {}, React menampilkannya sebagai teks biasa, bukan menjalankannya. Ini melindungi aplikasi dari serangan XSS secara default.
Contoh kode
// src/App.jsx, kartu profil yang memakai semua aturan JSX
const pengguna = {
nama: 'Dewi Lestari',
pekerjaan: 'Frontend Developer',
foto: 'https://i.pravatar.cc/120?img=5',
tahunMulai: 2021,
};
function hitungPengalaman(tahunMulai) {
return new Date().getFullYear() - tahunMulai;
}
export default function App() {
const warnaAksen = '#0ea5e9';
const pengalaman = hitungPengalaman(pengguna.tahunMulai);
// Satu root: Fragment membungkus dua elemen sejajar
return (
<>
{/* Ini komentar di dalam JSX */}
<section className="kartu-profil" style={{ border: `2px solid ${warnaAksen}`, padding: 16 }}>
<img src={pengguna.foto} alt={`Foto ${pengguna.nama}`} width={120} />
<h2>{pengguna.nama}</h2>
<p>{pengguna.pekerjaan}</p>
<p>Pengalaman: {pengalaman} tahun</p>
<p>Nama dalam huruf besar: {pengguna.nama.toUpperCase()}</p>
</section>
<form>
<label htmlFor="pesan">Kirim pesan</label>
<input id="pesan" type="text" maxLength={100} placeholder="Tulis di sini" />
</form>
</>
);
}
// → Tampil kartu dengan border biru, foto, nama, pekerjaan,
// "Nama dalam huruf besar: DEWI LESTARI", dan form di bawahnya.
Logika if ditulis di luar JSX, sebelum return:
export default function Sapaan() {
const jam = new Date().getHours();
let salam;
if (jam < 11) {
salam = 'Selamat pagi';
} else if (jam < 15) {
salam = 'Selamat siang';
} else if (jam < 18) {
salam = 'Selamat sore';
} else {
salam = 'Selamat malam';
}
return <h1>{salam}, selamat belajar React!</h1>;
}
// Jam 09.00 → "Selamat pagi, selamat belajar React!"
Teks berbahaya otomatis aman:
export default function Komentar() {
const isiDariUser = '<script>alert("hack")</script>';
return <p>{isiDariUser}</p>;
}
// → Ditampilkan sebagai teks: <script>alert("hack")</script> (tidak dijalankan)
Kesalahan umum
- Mengembalikan dua elemen sejajar tanpa pembungkus. Error "Adjacent JSX elements must be wrapped in an enclosing tag". Bungkus dengan
<>...</>atau satu elemen induk. - Menulis
classataufor. PakaiclassNamedanhtmlFor. React memberi peringatan di console jika kamu lupa. - Memberi tanda kutip pada ekspresi.
src="{foto}"menghasilkan teks literal{foto}. Yang benarsrc={foto}. - Menulis
ifataufordi dalam{}. Kurung kurawal hanya menerima ekspresi. Pakai ternary,&&,map, atau pindahkan logika ke atasreturn. - Menulis style sebagai string.
style="color: red"error. Pakai objekstyle={{ color: 'red' }}.
Latihan
- Mudah, Ubah potongan HTML ini menjadi JSX yang valid:
<div class="box"><label for="nama">Nama</label><input type="text" id="nama"><br></div>. - Sedang, Buat komponen
KartuProdukyang menampilkan nama, harga dalam format Rupiah (pakaitoLocaleString('id-ID')), dan diskon 10% yang dihitung di dalam{}. - Menantang, Buat komponen
Jamyang menampilkan tanggal hari ini dalam format Indonesia, dan memberi warna teks merah jika hari Minggu, hitam jika bukan. Logika warna ditulis di atasreturn, style memakai objek.
Lihat solusi
1.
export default function Form() {
return (
<div className="box">
<label htmlFor="nama">Nama</label>
<input type="text" id="nama" />
<br />
</div>
);
}
2.
export default function KartuProduk() {
const nama = 'Kopi Gayo 250g';
const harga = 85000;
return (
<article className="produk">
<h3>{nama}</h3>
<p>Harga: Rp {harga.toLocaleString('id-ID')}</p>
<p>Setelah diskon 10%: Rp {(harga * 0.9).toLocaleString('id-ID')}</p>
</article>
);
}
// → Harga: Rp 85.000
// → Setelah diskon 10%: Rp 76.500
3.
export default function Jam() {
const hariIni = new Date();
const teks = hariIni.toLocaleDateString('id-ID', {
weekday: 'long', day: 'numeric', month: 'long', year: 'numeric',
});
const isMinggu = hariIni.getDay() === 0; // 0 = Minggu
const warna = isMinggu ? 'red' : 'black';
return <p style={{ color: warna, fontWeight: 'bold' }}>{teks}</p>;
}
// Kamis → "Kamis, 23 Oktober 2026" berwarna hitam
Ringkasan
- JSX adalah sintaks mirip HTML di dalam JavaScript; Vite mengubahnya menjadi JavaScript biasa.
- Komponen hanya mengembalikan satu elemen akar; pakai Fragment
<>...</>agar tidak menambah elemen DOM. - Pakai
className,htmlFor, dan atribut camelCase (onClick,maxLength); semua tag wajib ditutup. {}menerima ekspresi JavaScript, bukan pernyataan sepertiif/for; logika ditulis di atasreturn.stylemenerima objek dengan properti camelCase, dan komentar ditulis{/* ... */}.