Atribut data-* menyimpan data kustom langsung pada elemen HTML tanpa menyentuh atribut standar mana pun, sehingga markup tetap valid dan datanya ikut berpindah bersama elemennya. Nama atributnya bebas selama diawali data-, dan nilainya selalu berupa teks yang dibaca skrip saat halaman berjalan. Topik ini membahas aturan penamaannya, pembacaan dan penulisan melalui objek dataset di JavaScript, konversi kebab-case menjadi camelCase, serta batasan kapan data-* tepat digunakan dan kapan keadaan lebih baik disimpan di skrip. Setelah membacanya, penghubungan markup dan skrip dapat dilakukan tanpa mengotori atribut bawaan elemen.
Sintaks dan aturan penamaan data-*#
Atribut kustom adalah atribut yang namanya diawali data- dan disusuri setidaknya satu karakter lagi. Namanya hanya boleh memuat huruf kecil, angka, tanda hubung, dan beberapa tanda baca yang aman. Huruf kapital tidak diperkenankan karena HTML mengubah nama atribut menjadi huruf kecil saat penguraian, sehingga huruf kapital yang ditulis hilang tanpa pesan error. Nilainya berupa teks polos, dan atribut semacam ini sah pada semua elemen tanpa perlu deklarasi apa pun.
<ul>
<li class="kartu-buku" data-id="12" data-tahun="2019" data-rak="A2" data-halaman="328">
Panduan pengukuran cuaca
</li>
<li class="kartu-buku" data-id="13" data-tahun="2021" data-rak="B1" data-halaman="212">
Pengantar ilmu peta
</li>
</ul>Data yang disimpan semacam ini bukan tampilan, melainkan keterangan tambahan yang ditujukan kepada skrip, misalnya penanda rak dan jumlah halaman yang tidak perlu diperlihatkan kepada pembaca. Karena data itu melekat pada elemennya, skrip tidak perlu menyimpan pemetaan manual antara elemen dan data, dan markup yang dirender dari server dapat membawa data tersebut sejak awal. Inilah posisi data-* sebagai jembatan antara markup yang ditulis dan skrip yang memprosesnya.
Membaca dan menulis lewat dataset#
JavaScript mengakses atribut data-* melalui properti dataset pada elemen, yaitu objek yang memetakan setiap atribut menjadi kunci berbentuk camelCase. Membaca dataset.rak mengembalikan teks A2, dan menuliskan nilai baru pada objek itu langsung memperbarui atributnya di markup. Skrip berikut memperlihatkan pembacaan dan penulisannya, dan skrip ini menggunakan API browser sehingga hanya dapat berjalan di browser, bukan di Node.
// tidak-dijalankan
const kartu = document.querySelector(".kartu-buku");
// membaca atribut data-rak lewat dataset
console.log(kartu.dataset.rak);
// menulis nilai baru: atribut data-status="dipinjam" muncul di markup
kartu.dataset.status = "dipinjam";
console.log(kartu.getAttribute("data-status"));
// menghapus atribut data-tahun dari elemen
delete kartu.dataset.tahun;Objek dataset dan fungsi getAttribute menunjuk data yang sama, sehingga keduanya dapat digunakan bergantian sesuai kenyamanan. Perbedaannya terletak pada bentuk namanya, karena getAttribute("data-tahun") menggunakan nama atribut lengkapnya, sedangkan dataset menggunakan kunci camelCase tanpa awalan data-. Menghapus kunci pada dataset menghilangkan atributnya dari elemen, sehingga pembersihan data tidak perlu memanipulasi markup secara manual.
Konvensi kebab-case menjadi camelCase#
Nama atribut data-* ditulis kebab-case di markup, sedangkan kuncinya menjadi camelCase di dataset, dan aturan konversinya mekanis. Setiap tanda hubung yang diikuti huruf kecil dihapus, dan huruf sesudahnya dikapitalisasi, sehingga data-tanggal-pinjam dibaca sebagai dataset.tanggalPinjam. Aturan ini berlaku dua arah pada pembacaan dan penulisan, tetapi nama yang mengandung huruf kapital tidak mengikuti aturan tersebut dan justru menjadi tidak sah di markup.
Skrip berikut memvalidasi nama atribut data-* dari potongan markup sekaligus menghitung kunci datasetnya, sehingga kedua sisi konvensi itu terlihat berdampingan. Aturan konversinya ditulis persis seperti yang dilakukan browser, yaitu tanda hubung yang diikuti huruf kecil dihapus, lalu huruf sesudahnya dikapitalisasi.
// Memeriksa nama atribut data-* dari potongan markup
// dan menghitung kunci dataset-nya
const markup = `
<article class="kartu" data-id="12" data-tanggal-pinjam="2026-05-04"
data-kelas-tujuh="3A" data-="kosong" data-JumlahHalaman="96"></article>`;
const atribut = [...markup.matchAll(/\s([a-zA-Z][a-zA-Z0-9-]*)="([^"]*)"/g)];
for (const [, nama, nilai] of atribut) {
if (!nama.startsWith("data-")) continue;
const bagian = nama.slice(5);
if (bagian === "") {
console.log(`${nama} : TIDAK valid, setidaknya satu karakter setelah data-`);
} else if (/[A-Z]/.test(nama)) {
console.log(`${nama} : TIDAK valid, huruf kapital dilowercase oleh browser`);
} else {
const kunci = bagian.replace(/-([a-z])/g, (_, huruf) => huruf.toUpperCase());
console.log(`${nama} : valid, dataset.${kunci} = "${nilai}"`);
}
}data-id : valid, dataset.id = "12"
data-tanggal-pinjam : valid, dataset.tanggalPinjam = "2026-05-04"
data-kelas-tujuh : valid, dataset.kelasTujuh = "3A"
data- : TIDAK valid, setidaknya satu karakter setelah data-
data-JumlahHalaman : TIDAK valid, huruf kapital dilowercase oleh browserKeluaran tersebut memperlihatkan dua penolakan yang lazim ditemukan pada markup nyata, yaitu awalan data- yang dibiarkan kosong dan nama yang menyalin gaya camelCase langsung ke atribut. Tiga nama yang sah menghasilkan kunci yang terbaca alami pada objek dataset, dan konversinya persis seperti yang diterapkan skripnya. Apabila suatu nama memuat tanda hubung yang diikuti angka, tanda hubung itu tetap tersisa pada kuncinya, dan aksesnya pun harus menggunakan tanda kurung siku.
Kapan data-* tepat dan kapan bukan#
Atribut data-* paling tepat untuk data yang melekat pada elemen tertentu di dalam dokumen dan nilainya tetap selama markup itu hidup, misalnya penanda rak pada daftar buku atau status awal sebuah widget. Penggunaan ini menggantikan pola lama yang memanfaatkan atribut rel atau class untuk menyimpan keterangan, dan pola lama semacam itu memaksa dua maksud berbeda menumpang satu atribut. Dengan data-*, makna class kembali murni untuk gaya, sedangkan datanya menumpang pada atribut yang memang disediakan untuk itu.
Sebaliknya, keadaan yang berubah-ubah selama aplikasi berjalan lebih baik disimpan dalam variabel skrip, lalu dituliskan ke markup hanya saat perlu dirender. Menjadikan data-* sebagai tempat penyimpanan utama seluruh keadaan aplikasi menimbulkan penguraian teks yang berulang, karena nilainya selalu berupa string dan setiap pembacaan menuntut pengubahan tipe. Kaidah praktisnya, data yang datang bersama markup disimpan pada markup, sedangkan data yang lahir dari interaksi disimpan pada skrip dan hanya dituliskan ke data-* bila dibutuhkan elemen lain.
Berkas utuh pemanfaatan data-*#
Berkas berikut menerapkan data-* pada daftar buku tandon perpustakaan, lengkap dengan skrip yang menghitung rata-rata halaman rak A2 dari atribut data-rak dan data-halaman. Seluruh data berada di markup, sedangkan skrip hanya membaca dan menjumlahkan, dan pola inilah bentuk kerja sama yang dimaksud dengan penghubungan markup dan skrip.
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Contoh atribut data-*</title>
<style>
body { font-family: sans-serif; max-width: 34rem; margin: 0 auto; padding: 0 1rem; }
ul { list-style: none; padding: 0; }
li { border: 1px solid #cbd5e1; border-radius: 4px; padding: 0.5rem 0.75rem; margin-bottom: 0.5rem; }
button { padding: 0.4rem 0.8rem; font-size: 1rem; }
#hasil { font-weight: 600; }
</style>
</head>
<body>
<h1>Koleksi tandon buku</h1>
<ul id="daftar-buku">
<li class="kartu-buku" data-id="12" data-tahun="2019" data-rak="A2" data-halaman="328">
Panduan pengukuran cuaca
</li>
<li class="kartu-buku" data-id="13" data-tahun="2021" data-rak="B1" data-halaman="212">
Pengantar ilmu peta
</li>
<li class="kartu-buku" data-id="14" data-tahun="2024" data-rak="A2" data-halaman="180">
Catatan pengamat langit
</li>
</ul>
<button type="button" id="hitung">Hitung rata-rata halaman rak A2</button>
<p id="hasil"></p>
<script>
document.querySelector("#hitung").addEventListener("click", () => {
const kartu = document.querySelectorAll(".kartu-buku");
let jumlah = 0;
let total = 0;
for (const kartuBuku of kartu) {
if (kartuBuku.dataset.rak === "A2") {
jumlah += 1;
total += Number(kartuBuku.dataset.halaman);
}
}
const rataRata = jumlah > 0 ? total / jumlah : 0;
document.querySelector("#hasil").textContent =
`Rak A2 berisi ${jumlah} buku dengan rata-rata ${rataRata.toFixed(0)} halaman.`;
});
</script>
</body>
</html>Buka berkasnya di browser lalu tekan tombol penghitungnya, dan hasil yang tampil adalah dua buku dengan rata-rata 254 halaman, yaitu hasil penjumlahan 328 dan 180 yang dibagi dua. Ubah salah satu data-halaman pada berkasnya lalu muat ulang, dan hasil penghitungan ikut berubah tanpa menyentuh satu baris skrip pun, yang menandakan data memang tersimpan di markup.
Kesalahan umum#
- Menuliskan nama atribut dengan huruf kapital, misalnya
data-jumlahHalaman. Browser mengubah namanya menjadi huruf kecil saat penguraian, sehinggadataset.jumlahHalamanyang diharapkan tidak pernah muncul. Gunakan kebab-case di markup dan biarkandatasetyang mengkapitalkannya. - Menyimpan data yang sering berubah di
data-*lalu membacanya berulang kali. Nilainya selalu string, sehingga setiap baca menuntut pengubahan tipe dan rentan keliru. Simpan keadaan yang dinamis di skrip. - Menumpuk data ke atribut standar seperti
classataurel. Dua maksud dalam satu atribut saling mengganggu, misalnya gaya yang tidak sengaja terpicu oleh penanda data. Gunakandata-*yang memang disediakan untuk data kustom. - Mengharuskan
data-*pada elemen demi elemen padahal nilainya seragam untuk semua elemen. Nilai yang sama untuk semua butir lebih tepat menjadi satu konstanta di skrip atau satu kelas CSS.
Ringkasan#
- Atribut
data-*menyimpan data kustom berupa teks pada elemen mana pun, dengan nama kebab-case yang tidak memuat huruf kapital. - Objek
datasetmembaca dan menulis atribut tersebut sebagai kunci camelCase, dan menghapus kuncinya menghilangkan atributnya dari markup. - Konversi kebab-case ke camelCase berjalan mekanis, dan nama yang menyertai huruf kapital tidak sah di markup.
data-*tepat untuk data yang melekat pada markup, sedangkan keadaan yang berubah-ubah lebih baik disimpan di skrip.
Referensi#
- Atribut global data-* — MDN — Aturan penamaan atribut data-* beserta contoh penggunaannya.
- HTMLElement.dataset — MDN — Konversi kebab-case ke camelCase pada objek dataset.
- Embedding custom data — HTML Living Standard (WHATWG) — Spesifikasi atribut data-* dan aturan namanya.