Kartu produk di halaman Budi membawa data yang tidak terlihat di layar: tautan menuju detail, penanda kategori, sisa stok. Data-data itu tersimpan pada atribut — pasangan nama-nilai yang ditulis di tag HTML. Sementara di sisi JavaScript, elemen yang sama hadir sebagai object dengan properti berangka, dan beberapa properti itu ternyata terhubung dua arah dengan atributnya.

Hubungan atribut-properti adalah salah satu sumber kebingungan paling sering di materi DOM: kapan memakai setAttribute, kapan cukup menugaskan properti, dan mengapa input.value tidak mengubah atribut value. Chapter ini menuntaskannya dengan urutan berlapis: empat method atribut, lalu dataset, lalu properti refleksi.

Atribut vs Properti: Dua Lapis Nilai #

Satu elemen bisa dibaca dari dua lapis yang berbeda:

  • Atribut adalah nilai yang tertulis di tag HTML — bagian dari “dokumen”. Lapis ini dibaca lewat method seperti getAttribute.
  • Properti adalah field pada object JavaScript hasil representasi elemen — bagian dari “program”. Lapis ini dibaca seperti properti object biasa: input.value.

Banyak properti mengambil nilai awalnya dari atribut, lalu berjalan sendiri setelah halaman hidup. Karena itu dua lapis bisa berbeda isi — dan bagian akhir chapter membuktikannya dengan angka.

Empat Method Atribut #

Method berikut bekerja langsung pada lapis atribut, apa pun tipenya — atribut standar, atribut yang tidak dikenal browser, maupun data-*:

MethodTugasKembalian
getAttribute(nama)baca nilai atributstring, atau null bila tidak ada
setAttribute(nama, nilai)tulis atau ubah atributundefined
hasAttribute(nama)periksa keberadaantrue / false
removeAttribute(nama)hapus atributundefined

Berkas contoh memakai keempatnya sekaligus dengan dataset dan properti refleksi:

// atur-atribut.js — mengelola atribut, dataset, dan properti refleksi

const tautan = document.querySelector("#tautan");
const kartu = document.querySelector("#kartu");
const input = document.querySelector("#nama");

// 1. empat method atribut
console.log(tautan.getAttribute("href"));     // /beranda
tautan.setAttribute("title", "Ke beranda");
console.log(tautan.hasAttribute("title"));    // true
tautan.removeAttribute("title");
console.log(tautan.hasAttribute("title"));    // false
console.log(tautan.getAttribute("target"));   // null

// 2. dataset: data-* sebagai object
console.log(kartu.dataset.kategori);          // minuman
kartu.dataset.stok = "12";
console.log(kartu.getAttribute("data-stok")); // 12
kartu.dataset.unggulan = "";
console.log(kartu.hasAttribute("data-unggulan")); // true

// 3. properti refleksi: value
console.log(input.getAttribute("value"));     // Siti (nilai atribut awal)
input.setAttribute("value", "Budi Santoso");
console.log(input.value);                     // Budi Santoso (properti ikut)

// 4. properti refleksi: href
console.log(tautan.href);                     // URL absolut
tautan.href = "/produk";
console.log(tautan.href);                     // URL absolut yang baru

Output yang Dihasilkan (console browser):

text
/beranda
true
false
null
minuman
12
true
Siti
Budi Santoso
https://example.test/beranda
https://example.test/produk

Keluaran dicatat dari eksekusi nyata di lingkungan jsdom dengan alamat halaman https://example.test/; console browser memakai alamat halaman sungguhan sebagai dasar, sehingga dua baris terakhir berubah mengikuti alamat itu — sisanya identik. Mari kita bedah:

  1. Baris 8 (getAttribute("href")): nilai yang kembali adalah /beranda — persis string yang tertulis di tag, tanpa penambahan apa pun. Method atribut tidak pernah “memperbaiki” nilai.
  2. Baris 9–13 (set, has, remove): setAttribute("title", ...) menambah atribut baru; hasAttribute mengonfirmasi keberadaannya (true), lalu setelah removeAttribute, pemeriksaan yang sama mengembalikan false. Baris terakhir menunjukkan atribut yang tidak pernah ada: getAttribute("target") mengembalikan null.
  3. Baris 16–18 (dataset): properti dataset memetakan atribut data-* menjadi object — data-kategori terbaca sebagai dataset.kategori. Penugasan kartu.dataset.stok = "12" langsung menuliskan atribut data-stok, terbukti dari getAttribute("data-stok") yang kembali "12".
  4. Baris 19–20 (nilai kosong untuk atribut penanda): kartu.dataset.unggulan = "" menghasilkan atribut data-unggulan tanpa isi — pola lazim untuk penanda kehadiran (presence flag), diperiksa dengan hasAttribute.
  5. Baris 23–25 (refleksi satu arah: atribut → properti): atribut value awal berisi "Siti". Setelah setAttribute("value", "Budi Santoso"), properti input.value ikut berubah — inilah refleksi: perubahan di lapis atribut diteruskan ke lapis properti.
  6. Baris 28 (tautan.href getter): properti href tidak mengembalikan string mentah, melainkan URL yang sudah diurai (resolved) relatif terhadap alamat halaman — https://example.test/beranda.
  7. Baris 29–30 (refleksi dua arah: properti → atribut): penugasan tautan.href = "/produk" menuliskan kembali atribut di latar belakang, dan getter mengembalikan URL absolut yang baru. Properti ini selalu dinormalisasi, berbeda dari getAttribute yang menyimpan string mentah.

data-* dan dataset #

Atribut data-* adalah tempat resmi menyimpan data milik aplikasi di dalam HTML — kategori, stok, status — tanpa menyentuh atribut bawaan. Aturan penamaannya satu arah dan dapat diprediksi:

  • HTML: data-ubah-harga — huruf kecil, kata dipisah tanda hubung.
  • JavaScript: dataset.ubahHarga — tanda hubung dihapus, huruf berikutnya dikapitalkan (gaya camelCase).

Perhatikan batas arahnya: dataset tidak bisa menampung nama dengan huruf besar di HTML (atribut HTML tidak peka huruf besar-kecil), dan nilai di kedua sisi selalu bertipe string — angka 12 tersimpan sebagai "12". Konversi tipe dilakukan di kode JavaScript, bukan oleh dataset.

Karena dataset berperilaku seperti object biasa, isi satu elemen bisa dijajal dengan alat object standar:

js Menjajal seluruh data-* pada satu elemen
const kartu = document.querySelector("#kartu");
kartu.dataset.stok = "12";
kartu.dataset.unggulan = "";
console.log(Object.keys(kartu.dataset).join(",")); // kategori,stok,unggulan

Urutannya mengikuti urutan penambahan atribut — kategori dari markup, lalu stok dan unggulan dari kode. Pola semacam ini nyaman untuk menyalin seluruh data kartu ke suatu tempat lain tanpa menyebut nama atribut satu per satu; cukup pastikan penamaan data-* di markup sudah konsisten sejak awal.

Properti yang Merefleksikan Atribut #

Beberapa properti elemen dirancang sebagai cermin atributnya. Tiga yang paling sering dipakai:

PropertiAtribut yang dicerminkanCatatan perilaku
input.valuevalueproperti = nilai saat ini; atribut = nilai awal
tautan.hrefhrefgetter dan setter selalu bekerja dengan URL absolut
checkbox.checkedcheckedbertipe boolean, tidak pernah string

Kasus value layak digarisbawahi karena arah refleksinya asimetris. Ketika kita menugaskan input.value = "Rina" langsung — tanpa menyentuh atribut — atribut value di HTML tetap memegang nilai awalnya. Atribut itu memang berperan sebagai “nilai default”, bukan cermin terkini. Karena itu, bila ingin membaca apa yang benar-benar terkandung pada form saat itu, baca properti value, bukan getAttribute("value").

Kasus href menyimpan pelajaran serupa dari sisi lain. Atribut href menyimpan string apa adanya — boleh relatif seperti /beranda — sedangkan properti href selalu menormalkan menjadi URL lengkap dengan alamat halaman sebagai dasar. Dua pembacaan bisa menghasilkan string berbeda untuk tautan yang sama, dan keduanya benar: atribut mencatat apa yang tertulis, properti menyajikan makna yang dipakai browser. Bila markup memakai tag <base>, hasil penormalan properti mengikuti dasar itu pula.

Atribut dan dataset mengatur data pada elemen yang sudah ada. Pertanyaan berikutnya soal tampilan: bagaimana menandai status visual elemen tanpa menyentuh CSS satu baris pun — jawabannya class, bahasan chapter classList.

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

atur-atribut.js

Unduh berkas
javascript
// atur-atribut.js — mengelola atribut, dataset, dan properti refleksi

const tautan = document.querySelector("#tautan");
const kartu = document.querySelector("#kartu");
const input = document.querySelector("#nama");

// 1. empat method atribut
console.log(tautan.getAttribute("href"));     // /beranda
tautan.setAttribute("title", "Ke beranda");
console.log(tautan.hasAttribute("title"));    // true
tautan.removeAttribute("title");
console.log(tautan.hasAttribute("title"));    // false
console.log(tautan.getAttribute("target"));   // null

// 2. dataset: data-* sebagai object
console.log(kartu.dataset.kategori);          // minuman
kartu.dataset.stok = "12";
console.log(kartu.getAttribute("data-stok")); // 12
kartu.dataset.unggulan = "";
console.log(kartu.hasAttribute("data-unggulan")); // true

// 3. properti refleksi: value
console.log(input.getAttribute("value"));     // Siti (nilai atribut awal)
input.setAttribute("value", "Budi Santoso");
console.log(input.value);                     // Budi Santoso (properti ikut)

// 4. properti refleksi: href
console.log(tautan.href);                     // URL absolut
tautan.href = "/produk";
console.log(tautan.href);                     // URL absolut yang baru